OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Histogram is an object that aggregates statistics, and can summarize them in | 5 // Histogram is an object that aggregates statistics, and can summarize them in |
6 // various forms, including ASCII graphical, HTML, and numerically (as a | 6 // various forms, including ASCII graphical, HTML, and numerically (as a |
7 // vector of numbers corresponding to each of the aggregating buckets). | 7 // vector of numbers corresponding to each of the aggregating buckets). |
8 // See header file for details and examples. | 8 // See header file for details and examples. |
9 | 9 |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
(...skipping 886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
897 //------------------------------------------------------------------------------ | 897 //------------------------------------------------------------------------------ |
898 // The next section handles global (central) support for all histograms, as well | 898 // The next section handles global (central) support for all histograms, as well |
899 // as startup/teardown of this service. | 899 // as startup/teardown of this service. |
900 //------------------------------------------------------------------------------ | 900 //------------------------------------------------------------------------------ |
901 | 901 |
902 // This singleton instance should be started during the single threaded portion | 902 // This singleton instance should be started during the single threaded portion |
903 // of main(), and hence it is not thread safe. It initializes globals to | 903 // of main(), and hence it is not thread safe. It initializes globals to |
904 // provide support for all future calls. | 904 // provide support for all future calls. |
905 StatisticsRecorder::StatisticsRecorder() { | 905 StatisticsRecorder::StatisticsRecorder() { |
906 DCHECK(!histograms_); | 906 DCHECK(!histograms_); |
907 lock_ = new Lock; | 907 if (lock_ == NULL) { |
| 908 // This will leak on purpose. It's the only way to make sure we won't race |
| 909 // against the static uninitialization of the module while one of our |
| 910 // static methods relying on the lock get called at an inappropriate time |
| 911 // during the termination phase. Since it's a static data member, we will |
| 912 // leak one per process, which would be similar to the instance allocated |
| 913 // during static initialization and released only on process termination. |
| 914 lock_ = new Lock; |
| 915 } |
| 916 AutoLock auto_lock(*lock_); |
908 histograms_ = new HistogramMap; | 917 histograms_ = new HistogramMap; |
909 } | 918 } |
910 | 919 |
911 StatisticsRecorder::~StatisticsRecorder() { | 920 StatisticsRecorder::~StatisticsRecorder() { |
912 DCHECK(histograms_); | 921 DCHECK(histograms_ && lock_); |
913 | 922 |
914 if (dump_on_exit_) { | 923 if (dump_on_exit_) { |
915 std::string output; | 924 std::string output; |
916 WriteGraph("", &output); | 925 WriteGraph("", &output); |
917 LOG(INFO) << output; | 926 LOG(INFO) << output; |
918 } | 927 } |
919 // Clean up. | 928 // Clean up. |
920 delete histograms_; | 929 HistogramMap* histograms = NULL; |
921 histograms_ = NULL; | 930 { |
922 delete lock_; | 931 AutoLock auto_lock(*lock_); |
923 lock_ = NULL; | 932 histograms = histograms_; |
| 933 histograms_ = NULL; |
| 934 } |
| 935 delete histograms; |
| 936 // We don't delete lock_ on purpose to avoid having to properly protect |
| 937 // against it going away after we checked for NULL in the static methods. |
924 } | 938 } |
925 | 939 |
926 // static | 940 // static |
927 bool StatisticsRecorder::WasStarted() { | 941 bool StatisticsRecorder::IsActive() { |
| 942 if (lock_ == NULL) |
| 943 return false; |
| 944 AutoLock auto_lock(*lock_); |
928 return NULL != histograms_; | 945 return NULL != histograms_; |
929 } | 946 } |
930 | 947 |
931 // Note: We can't accept a ref_ptr to |histogram| because we *might* not keep a | 948 // Note: We can't accept a ref_ptr to |histogram| because we *might* not keep a |
932 // reference, and we are called while in the Histogram constructor. In that | 949 // reference, and we are called while in the Histogram constructor. In that |
933 // scenario, a ref_ptr would have incremented the ref count when the histogram | 950 // scenario, a ref_ptr would have incremented the ref count when the histogram |
934 // was passed to us, decremented it when we returned, and the instance would be | 951 // was passed to us, decremented it when we returned, and the instance would be |
935 // destroyed before assignment (when value was returned by new). | 952 // destroyed before assignment (when value was returned by new). |
936 // static | 953 // static |
937 void StatisticsRecorder::Register(Histogram* histogram) { | 954 void StatisticsRecorder::Register(Histogram* histogram) { |
| 955 if (lock_ == NULL) |
| 956 return; |
| 957 AutoLock auto_lock(*lock_); |
938 if (!histograms_) | 958 if (!histograms_) |
939 return; | 959 return; |
940 const std::string name = histogram->histogram_name(); | 960 const std::string name = histogram->histogram_name(); |
941 AutoLock auto_lock(*lock_); | |
942 // Avoid overwriting a previous registration. | 961 // Avoid overwriting a previous registration. |
943 if (histograms_->end() == histograms_->find(name)) | 962 if (histograms_->end() == histograms_->find(name)) |
944 (*histograms_)[name] = histogram; | 963 (*histograms_)[name] = histogram; |
945 } | 964 } |
946 | 965 |
947 // static | 966 // static |
948 void StatisticsRecorder::WriteHTMLGraph(const std::string& query, | 967 void StatisticsRecorder::WriteHTMLGraph(const std::string& query, |
949 std::string* output) { | 968 std::string* output) { |
950 if (!histograms_) | 969 if (!IsActive()) |
951 return; | 970 return; |
952 output->append("<html><head><title>About Histograms"); | 971 output->append("<html><head><title>About Histograms"); |
953 if (!query.empty()) | 972 if (!query.empty()) |
954 output->append(" - " + query); | 973 output->append(" - " + query); |
955 output->append("</title>" | 974 output->append("</title>" |
956 // We'd like the following no-cache... but it doesn't work. | 975 // We'd like the following no-cache... but it doesn't work. |
957 // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">" | 976 // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">" |
958 "</head><body>"); | 977 "</head><body>"); |
959 | 978 |
960 Histograms snapshot; | 979 Histograms snapshot; |
961 GetSnapshot(query, &snapshot); | 980 GetSnapshot(query, &snapshot); |
962 for (Histograms::iterator it = snapshot.begin(); | 981 for (Histograms::iterator it = snapshot.begin(); |
963 it != snapshot.end(); | 982 it != snapshot.end(); |
964 ++it) { | 983 ++it) { |
965 (*it)->WriteHTMLGraph(output); | 984 (*it)->WriteHTMLGraph(output); |
966 output->append("<br><hr><br>"); | 985 output->append("<br><hr><br>"); |
967 } | 986 } |
968 output->append("</body></html>"); | 987 output->append("</body></html>"); |
969 } | 988 } |
970 | 989 |
971 // static | 990 // static |
972 void StatisticsRecorder::WriteGraph(const std::string& query, | 991 void StatisticsRecorder::WriteGraph(const std::string& query, |
973 std::string* output) { | 992 std::string* output) { |
974 if (!histograms_) | 993 if (!IsActive()) |
975 return; | 994 return; |
976 if (query.length()) | 995 if (query.length()) |
977 StringAppendF(output, "Collections of histograms for %s\n", query.c_str()); | 996 StringAppendF(output, "Collections of histograms for %s\n", query.c_str()); |
978 else | 997 else |
979 output->append("Collections of all histograms\n"); | 998 output->append("Collections of all histograms\n"); |
980 | 999 |
981 Histograms snapshot; | 1000 Histograms snapshot; |
982 GetSnapshot(query, &snapshot); | 1001 GetSnapshot(query, &snapshot); |
983 for (Histograms::iterator it = snapshot.begin(); | 1002 for (Histograms::iterator it = snapshot.begin(); |
984 it != snapshot.end(); | 1003 it != snapshot.end(); |
985 ++it) { | 1004 ++it) { |
986 (*it)->WriteAscii(true, "\n", output); | 1005 (*it)->WriteAscii(true, "\n", output); |
987 output->append("\n"); | 1006 output->append("\n"); |
988 } | 1007 } |
989 } | 1008 } |
990 | 1009 |
991 // static | 1010 // static |
992 void StatisticsRecorder::GetHistograms(Histograms* output) { | 1011 void StatisticsRecorder::GetHistograms(Histograms* output) { |
| 1012 if (lock_ == NULL) |
| 1013 return; |
| 1014 AutoLock auto_lock(*lock_); |
993 if (!histograms_) | 1015 if (!histograms_) |
994 return; | 1016 return; |
995 AutoLock auto_lock(*lock_); | |
996 for (HistogramMap::iterator it = histograms_->begin(); | 1017 for (HistogramMap::iterator it = histograms_->begin(); |
997 histograms_->end() != it; | 1018 histograms_->end() != it; |
998 ++it) { | 1019 ++it) { |
999 DCHECK_EQ(it->first, it->second->histogram_name()); | 1020 DCHECK_EQ(it->first, it->second->histogram_name()); |
1000 output->push_back(it->second); | 1021 output->push_back(it->second); |
1001 } | 1022 } |
1002 } | 1023 } |
1003 | 1024 |
1004 bool StatisticsRecorder::FindHistogram(const std::string& name, | 1025 bool StatisticsRecorder::FindHistogram(const std::string& name, |
1005 scoped_refptr<Histogram>* histogram) { | 1026 scoped_refptr<Histogram>* histogram) { |
| 1027 if (lock_ == NULL) |
| 1028 return false; |
| 1029 AutoLock auto_lock(*lock_); |
1006 if (!histograms_) | 1030 if (!histograms_) |
1007 return false; | 1031 return false; |
1008 AutoLock auto_lock(*lock_); | |
1009 HistogramMap::iterator it = histograms_->find(name); | 1032 HistogramMap::iterator it = histograms_->find(name); |
1010 if (histograms_->end() == it) | 1033 if (histograms_->end() == it) |
1011 return false; | 1034 return false; |
1012 *histogram = it->second; | 1035 *histogram = it->second; |
1013 return true; | 1036 return true; |
1014 } | 1037 } |
1015 | 1038 |
1016 // private static | 1039 // private static |
1017 void StatisticsRecorder::GetSnapshot(const std::string& query, | 1040 void StatisticsRecorder::GetSnapshot(const std::string& query, |
1018 Histograms* snapshot) { | 1041 Histograms* snapshot) { |
| 1042 if (lock_ == NULL) |
| 1043 return; |
1019 AutoLock auto_lock(*lock_); | 1044 AutoLock auto_lock(*lock_); |
| 1045 if (!histograms_) |
| 1046 return; |
1020 for (HistogramMap::iterator it = histograms_->begin(); | 1047 for (HistogramMap::iterator it = histograms_->begin(); |
1021 histograms_->end() != it; | 1048 histograms_->end() != it; |
1022 ++it) { | 1049 ++it) { |
1023 if (it->first.find(query) != std::string::npos) | 1050 if (it->first.find(query) != std::string::npos) |
1024 snapshot->push_back(it->second); | 1051 snapshot->push_back(it->second); |
1025 } | 1052 } |
1026 } | 1053 } |
1027 | 1054 |
1028 // static | 1055 // static |
1029 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; | 1056 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; |
1030 // static | 1057 // static |
1031 Lock* StatisticsRecorder::lock_ = NULL; | 1058 Lock* StatisticsRecorder::lock_ = NULL; |
1032 // static | 1059 // static |
1033 bool StatisticsRecorder::dump_on_exit_ = false; | 1060 bool StatisticsRecorder::dump_on_exit_ = false; |
1034 | 1061 |
1035 } // namespace base | 1062 } // namespace base |
OLD | NEW |