Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/platform/metrics/metrics_daemon.cc

Issue 1799001: Log time between network drops -- from online to offline. (Closed) Base URL: ssh://git@chromiumos-git/chromeos
Patch Set: address review comments. Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/platform/metrics/metrics_daemon.h ('k') | src/platform/metrics/network_states.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium OS 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 #include "metrics_daemon.h" 5 #include "metrics_daemon.h"
6 #include "metrics_library.h" 6 #include "metrics_library.h"
7 7
8 #include <glib-object.h> 8 #include <dbus/dbus-glib-lowlevel.h>
9
10 extern "C" {
11 #include "marshal_void__string_boxed.h"
12 }
13 9
14 #include <base/logging.h> 10 #include <base/logging.h>
15 11
16 #define SAFE_MESSAGE(e) ((e && e->message) ? e->message : "unknown error") 12 #define SAFE_MESSAGE(e) (e.message ? e.message : "unknown error")
13 #define DBUS_IFACE_CONNMAN_MANAGER "org.moblin.connman.Manager"
14 #define DBUS_IFACE_POWER_MANAGER "org.chromium.Power.Manager"
17 15
18 MetricsDaemon::NetworkState 16 // static
17 const char*
18 MetricsDaemon::dbus_matches_[] = {
19 "type='signal',"
20 "sender='org.moblin.connman',"
21 "interface='" DBUS_IFACE_CONNMAN_MANAGER "',"
22 "path='/',"
23 "member='StateChanged'",
24
25 "type='signal',"
26 "interface='" DBUS_IFACE_POWER_MANAGER "',"
27 "path='/',"
28 "member='PowerStateChanged'",
29 };
30
31 // static
32 const char *
19 MetricsDaemon::network_states_[MetricsDaemon::kNumberNetworkStates] = { 33 MetricsDaemon::network_states_[MetricsDaemon::kNumberNetworkStates] = {
20 #define STATE(name, capname) { #name, "Network.Connman" # capname }, 34 #define STATE(name, capname) #name,
21 #include "network_states.h" 35 #include "network_states.h"
22 }; 36 };
23 37
38 // static
39 const char *
40 MetricsDaemon::power_states_[MetricsDaemon::kNumberPowerStates] = {
41 #define STATE(name, capname) #name,
42 #include "power_states.h"
43 };
44
24 void MetricsDaemon::Run(bool run_as_daemon, bool testing) { 45 void MetricsDaemon::Run(bool run_as_daemon, bool testing) {
25 Init(testing); 46 Init(testing);
26 if (!run_as_daemon || daemon(0, 0) == 0) { 47 if (!run_as_daemon || daemon(0, 0) == 0) {
27 Loop(); 48 Loop();
28 } 49 }
29 } 50 }
30 51
31 void MetricsDaemon::Init(bool testing) { 52 void MetricsDaemon::Init(bool testing) {
32 testing_ = testing; 53 testing_ = testing;
33 network_state_id_ = kUnknownNetworkStateId; 54 network_state_ = kUnknownNetworkState;
55 network_state_changed_ = 0;
56 power_state_ = kUnknownPowerState;
34 57
35 ::g_thread_init(NULL); 58 g_thread_init(NULL);
36 ::g_type_init(); 59 g_type_init();
37 ::dbus_g_thread_init(); 60 dbus_g_thread_init();
38 61
39 ::GError* error = NULL; 62 DBusError error;
40 ::DBusGConnection* dbc = ::dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); 63 dbus_error_init(&error);
41 // Note that LOG(FATAL) terminates the process; otherwise we'd have to worry
42 // about leaking |error|.
43 LOG_IF(FATAL, dbc == NULL) <<
44 "cannot connect to dbus: " << SAFE_MESSAGE(error);
45 64
46 ::DBusGProxy* net_proxy = ::dbus_g_proxy_new_for_name( 65 DBusConnection *connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
47 dbc, "org.moblin.connman", "/", "org.moblin.connman.Metrics"); 66 LOG_IF(FATAL, dbus_error_is_set(&error)) <<
48 LOG_IF(FATAL, net_proxy == NULL) << "no dbus proxy for network"; 67 "No D-Bus connection: " << SAFE_MESSAGE(error);
49 68
50 #if 0 69 dbus_connection_setup_with_g_main(connection, NULL);
51 // Unclear how soon one can call dbus_g_type_get_map(). Doing it before the
52 // call to dbus_g_bus_get() results in a (non-fatal) assertion failure.
53 // GetProperties returns a hash table.
54 hashtable_gtype = ::dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
55 G_TYPE_VALUE);
56 #endif
57 70
58 dbus_g_object_register_marshaller(marshal_VOID__STRING_BOXED, 71 // Registers D-Bus matches for the signals we would like to catch.
59 G_TYPE_NONE, 72 for (unsigned int m = 0; m < sizeof(dbus_matches_) / sizeof(char *); m++) {
60 G_TYPE_STRING, 73 const char* match = dbus_matches_[m];
61 G_TYPE_VALUE, 74 LOG(INFO) << "adding dbus match: " << match;
62 G_TYPE_INVALID); 75 dbus_bus_add_match(connection, match, &error);
63 ::dbus_g_proxy_add_signal(net_proxy, "ConnectionStateChanged", 76 LOG_IF(FATAL, dbus_error_is_set(&error)) <<
64 G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID); 77 "unable to add a match: " << SAFE_MESSAGE(error);
65 ::dbus_g_proxy_connect_signal(net_proxy, "ConnectionStateChanged", 78 }
66 G_CALLBACK(&StaticNetSignalHandler), 79
67 this, NULL); 80 // Adds the D-Bus filter routine to be called back whenever one of
81 // the registered D-Bus matches is successful. The daemon is not
82 // activated for D-Bus messages that don't match.
83 CHECK(dbus_connection_add_filter(connection, MessageFilter, this, NULL));
68 } 84 }
69 85
70 void MetricsDaemon::Loop() { 86 void MetricsDaemon::Loop() {
71 ::GMainLoop* loop = ::g_main_loop_new(NULL, false); 87 GMainLoop* loop = g_main_loop_new(NULL, false);
72 ::g_main_loop_run(loop); 88 g_main_loop_run(loop);
73 } 89 }
74 90
75 void MetricsDaemon::StaticNetSignalHandler(::DBusGProxy* proxy, 91 // static
76 const char* property, 92 DBusHandlerResult MetricsDaemon::MessageFilter(DBusConnection* connection,
77 const ::GValue* value, 93 DBusMessage* message,
78 void *data) { 94 void* user_data) {
79 (static_cast<MetricsDaemon*>(data))->NetSignalHandler(proxy, property, value); 95 LOG(INFO) << "message filter";
96
97 int message_type = dbus_message_get_type(message);
98 if (message_type != DBUS_MESSAGE_TYPE_SIGNAL) {
99 LOG(WARNING) << "unexpected message type " << message_type;
100 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
101 }
102
103 // Signal messages always have interfaces.
104 const char* interface = dbus_message_get_interface(message);
105 CHECK(interface != NULL);
106
107 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(user_data);
108
109 DBusMessageIter iter;
110 dbus_message_iter_init(message, &iter);
111 if (strcmp(interface, DBUS_IFACE_CONNMAN_MANAGER) == 0) {
112 CHECK(strcmp(dbus_message_get_member(message), "StateChanged") == 0);
113
114 char *state_name;
115 dbus_message_iter_get_basic(&iter, &state_name);
116 daemon->NetStateChanged(state_name);
117 } else if (strcmp(interface, DBUS_IFACE_POWER_MANAGER) == 0) {
118 CHECK(strcmp(dbus_message_get_member(message), "PowerStateChanged") == 0);
119
120 char *state_name;
121 dbus_message_iter_get_basic(&iter, &state_name);
122 daemon->PowerStateChanged(state_name);
123 } else {
124 LOG(WARNING) << "unexpected interface: " << interface;
125 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
126 }
127
128 return DBUS_HANDLER_RESULT_HANDLED;
80 } 129 }
81 130
82 void MetricsDaemon::NetSignalHandler(::DBusGProxy* proxy, 131 void MetricsDaemon::NetStateChanged(const char* state_name) {
83 const char* property, 132 LOG(INFO) << "network state: " << state_name;
84 const ::GValue* value) { 133
85 if (strcmp("ConnectionState", property) != 0) { 134 time_t now = time(NULL);
86 return; 135 NetworkState state = LookupNetworkState(state_name);
136
137 // Logs the time in seconds between the network going online to
138 // going offline in order to measure the mean time to network
139 // dropping. Going offline as part of suspend-to-RAM is not logged
140 // as network drop -- the assumption is that the message for
141 // suspend-to-RAM comes before the network offline message which
142 // seems to and should be the case.
143 if (state == kNetworkStateOffline &&
144 network_state_ == kNetworkStateOnline &&
145 power_state_ != kPowerStateMem) {
146 int online_time = static_cast<int>(now - network_state_changed_);
147 PublishMetric("Network.TimeToDrop", online_time,
148 1, 8 /* hours */ * 60 * 60, 50);
87 } 149 }
88 150
89 const char* newstate = static_cast<const char*>(g_value_get_string(value)); 151 network_state_ = state;
90 LogNetworkStateChange(newstate); 152 network_state_changed_ = now;
91 } 153 }
92 154
93 void MetricsDaemon::LogNetworkStateChange(const char* newstate) { 155 MetricsDaemon::NetworkState
94 NetworkStateId new_id = GetNetworkStateId(newstate); 156 MetricsDaemon::LookupNetworkState(const char* state_name) {
95 if (new_id == kUnknownNetworkStateId) { 157 for (int i = 0; i < kNumberNetworkStates; i++) {
96 LOG(WARNING) << "unknown network connection state " << newstate; 158 if (strcmp(state_name, network_states_[i]) == 0) {
97 return; 159 return static_cast<NetworkState>(i);
160 }
98 } 161 }
99 NetworkStateId old_id = network_state_id_; 162 LOG(WARNING) << "unknown network connection state: " << state_name;
100 if (new_id == old_id) { // valid new state and no change 163 return kUnknownNetworkState;
101 return;
102 }
103 struct timeval now;
104 if (gettimeofday(&now, NULL) != 0) {
105 PLOG(WARNING) << "gettimeofday";
106 }
107 if (old_id != kUnknownNetworkStateId) {
108 struct timeval diff;
109 timersub(&now, &network_state_start_, &diff);
110 int diff_ms = diff.tv_usec / 1000 + diff.tv_sec * 1000;
111 // Saturates rather than overflowing. We expect this to be statistically
112 // insignificant, since INT_MAX milliseconds is 24.8 days.
113 if (diff.tv_sec >= INT_MAX / 1000) {
114 diff_ms = INT_MAX;
115 }
116 PublishMetric(network_states_[old_id].stat_name,
117 diff_ms,
118 1,
119 8 * 60 * 60 * 1000, // 8 hours in milliseconds
120 100);
121 }
122 network_state_id_ = new_id;
123 network_state_start_ = now;
124 } 164 }
125 165
126 MetricsDaemon::NetworkStateId 166 void MetricsDaemon::PowerStateChanged(const char* state_name) {
127 MetricsDaemon::GetNetworkStateId(const char* state_name) { 167 LOG(INFO) << "power state: " << state_name;
128 for (int i = 0; i < kNumberNetworkStates; i++) { 168 power_state_ = LookupPowerState(state_name);
129 if (strcmp(state_name, network_states_[i].name) == 0) { 169 }
130 return static_cast<NetworkStateId>(i); 170
171 MetricsDaemon::PowerState
172 MetricsDaemon::LookupPowerState(const char* state_name) {
173 for (int i = 0; i < kNumberPowerStates; i++) {
174 if (strcmp(state_name, power_states_[i]) == 0) {
175 return static_cast<PowerState>(i);
131 } 176 }
132 } 177 }
133 return static_cast<NetworkStateId>(-1); 178 LOG(WARNING) << "unknown power state: " << state_name;
179 return kUnknownPowerState;
134 } 180 }
135 181
136 void MetricsDaemon::PublishMetric(const char* name, int sample, 182 void MetricsDaemon::PublishMetric(const char* name, int sample,
137 int min, int max, int nbuckets) { 183 int min, int max, int nbuckets) {
138 if (testing_) { 184 LOG(INFO) << "received metric: " << name << " " << sample <<
139 LOG(INFO) << "received metric: " << name << " " << sample << 185 " " << min << " " << max << " " << nbuckets;
140 " " << min << " " << max << " " << nbuckets; 186 if (!testing_) {
141 } else {
142 MetricsLibrary::SendToChrome(name, sample, min, max, nbuckets); 187 MetricsLibrary::SendToChrome(name, sample, min, max, nbuckets);
143 } 188 }
144 } 189 }
OLDNEW
« no previous file with comments | « src/platform/metrics/metrics_daemon.h ('k') | src/platform/metrics/network_states.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698