1 /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  */
5 
6 #include <errno.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <syslog.h>
10 
11 #include "cras_metrics.h"
12 #include "cras_main_message.h"
13 #include "cras_rstream.h"
14 
15 const char kHighestInputHardwareLevel[] = "Cras.HighestInputHardwareLevel";
16 const char kHighestOutputHardwareLevel[] = "Cras.HighestOutputHardwareLevel";
17 const char kNoCodecsFoundMetric[] = "Cras.NoCodecsFoundAtBoot";
18 const char kStreamTimeoutMilliSeconds[] = "Cras.StreamTimeoutMilliSeconds";
19 const char kStreamCallbackThreshold[] = "Cras.StreamCallbackThreshold";
20 const char kStreamFlags[] = "Cras.StreamFlags";
21 const char kStreamSamplingFormat[] = "Cras.StreamSamplingFormat";
22 const char kStreamSamplingRate[] = "Cras.StreamSamplingRate";
23 const char kUnderrunsPerDevice[] = "Cras.UnderrunsPerDevice";
24 
25 /* Type of metrics to log. */
26 enum CRAS_SERVER_METRICS_TYPE {
27 	HIGHEST_INPUT_HW_LEVEL,
28 	HIGHEST_OUTPUT_HW_LEVEL,
29 	LONGEST_FETCH_DELAY,
30 	NUM_UNDERRUNS,
31 	STREAM_CONFIG
32 };
33 
34 struct cras_server_metrics_stream_config {
35 	unsigned cb_threshold;
36 	unsigned flags;
37 	int format;
38 	unsigned rate;
39 };
40 
41 union cras_server_metrics_data {
42 	unsigned value;
43 	struct cras_server_metrics_stream_config stream_config;
44 };
45 
46 struct cras_server_metrics_message {
47 	struct cras_main_message header;
48 	enum CRAS_SERVER_METRICS_TYPE metrics_type;
49 	union cras_server_metrics_data data;
50 };
51 
init_server_metrics_msg(struct cras_server_metrics_message * msg,enum CRAS_SERVER_METRICS_TYPE type,union cras_server_metrics_data data)52 static void init_server_metrics_msg(
53 		struct cras_server_metrics_message *msg,
54 		enum CRAS_SERVER_METRICS_TYPE type,
55 		union cras_server_metrics_data data)
56 {
57 	memset(msg, 0, sizeof(*msg));
58 	msg->header.type = CRAS_MAIN_METRICS;
59 	msg->header.length = sizeof(*msg);
60 	msg->metrics_type = type;
61 	msg->data = data;
62 }
63 
cras_server_metrics_highest_hw_level(unsigned hw_level,enum CRAS_STREAM_DIRECTION direction)64 int cras_server_metrics_highest_hw_level(unsigned hw_level,
65 		enum CRAS_STREAM_DIRECTION direction)
66 {
67 	struct cras_server_metrics_message msg;
68 	union cras_server_metrics_data data;
69 	int err;
70 
71 	data.value = hw_level;
72 
73 	switch (direction) {
74 	case CRAS_STREAM_INPUT:
75 		init_server_metrics_msg(&msg, HIGHEST_INPUT_HW_LEVEL, data);
76 		break;
77 	case CRAS_STREAM_OUTPUT:
78 		init_server_metrics_msg(&msg, HIGHEST_OUTPUT_HW_LEVEL, data);
79 		break;
80 	default:
81 		return 0;
82 	}
83 
84 	err = cras_main_message_send((struct cras_main_message *)&msg);
85 	if (err < 0) {
86 		syslog(LOG_ERR,
87 		       "Failed to send metrics message: HIGHEST_HW_LEVEL");
88 		return err;
89 	}
90 
91 	return 0;
92 }
93 
cras_server_metrics_longest_fetch_delay(unsigned delay_msec)94 int cras_server_metrics_longest_fetch_delay(unsigned delay_msec)
95 {
96 	struct cras_server_metrics_message msg;
97 	union cras_server_metrics_data data;
98 	int err;
99 
100 	data.value = delay_msec;
101 	init_server_metrics_msg(&msg, LONGEST_FETCH_DELAY, data);
102 	err = cras_main_message_send((struct cras_main_message *)&msg);
103 	if (err < 0) {
104 		syslog(LOG_ERR,
105 		       "Failed to send metrics message: LONGEST_FETCH_DELAY");
106 		return err;
107 	}
108 
109 	return 0;
110 }
111 
cras_server_metrics_num_underruns(unsigned num_underruns)112 int cras_server_metrics_num_underruns(unsigned num_underruns)
113 {
114 	struct cras_server_metrics_message msg;
115 	union cras_server_metrics_data data;
116 	int err;
117 
118 	data.value = num_underruns;
119 	init_server_metrics_msg(&msg, NUM_UNDERRUNS, data);
120 	err = cras_main_message_send((struct cras_main_message *)&msg);
121 	if (err < 0) {
122 		syslog(LOG_ERR,
123 		       "Failed to send metrics message: NUM_UNDERRUNS");
124 		return err;
125 	}
126 
127 	return 0;
128 }
129 
cras_server_metrics_stream_config(struct cras_rstream_config * config)130 int cras_server_metrics_stream_config(struct cras_rstream_config *config)
131 {
132 	struct cras_server_metrics_message msg;
133 	union cras_server_metrics_data data;
134 	int err;
135 
136 	data.stream_config.cb_threshold = (unsigned)config->cb_threshold;
137 	data.stream_config.flags = (unsigned)config->flags;
138 	data.stream_config.format = (int)config->format->format;
139 	data.stream_config.rate = (unsigned)config->format->frame_rate;
140 
141 	init_server_metrics_msg(&msg, STREAM_CONFIG, data);
142 	err = cras_main_message_send((struct cras_main_message *)&msg);
143 	if (err < 0) {
144 		syslog(LOG_ERR,
145 			"Failed to send metrics message: STREAM_CONFIG");
146 		return err;
147 	}
148 
149 	return 0;
150 }
151 
metrics_stream_config(struct cras_server_metrics_stream_config config)152 static void metrics_stream_config(
153 		struct cras_server_metrics_stream_config config)
154 {
155 	/* Logs stream callback threshold. */
156 	cras_metrics_log_sparse_histogram(kStreamCallbackThreshold,
157 					  config.cb_threshold);
158 
159 	/* Logs stream flags. */
160 	cras_metrics_log_sparse_histogram(kStreamFlags,
161 					  config.flags);
162 
163 	/* Logs stream sampling format. */
164 	cras_metrics_log_sparse_histogram(kStreamSamplingFormat,
165 					  config.format);
166 
167 	/* Logs stream sampling rate. */
168 	cras_metrics_log_sparse_histogram(kStreamSamplingRate,
169 					  config.rate);
170 }
171 
handle_metrics_message(struct cras_main_message * msg,void * arg)172 static void handle_metrics_message(struct cras_main_message *msg, void *arg)
173 {
174 	struct cras_server_metrics_message *metrics_msg =
175 			(struct cras_server_metrics_message *)msg;
176 	switch (metrics_msg->metrics_type) {
177 	case HIGHEST_INPUT_HW_LEVEL:
178 		cras_metrics_log_histogram(kHighestInputHardwareLevel,
179 				metrics_msg->data.value, 1, 10000, 20);
180 		break;
181 	case HIGHEST_OUTPUT_HW_LEVEL:
182 		cras_metrics_log_histogram(kHighestOutputHardwareLevel,
183 				metrics_msg->data.value, 1, 10000, 20);
184 		break;
185 	case LONGEST_FETCH_DELAY:
186 		cras_metrics_log_histogram(kStreamTimeoutMilliSeconds,
187 				metrics_msg->data.value, 1, 20000, 10);
188 		break;
189 	case NUM_UNDERRUNS:
190 		cras_metrics_log_histogram(kUnderrunsPerDevice,
191 				metrics_msg->data.value, 0, 1000, 10);
192 		break;
193 	case STREAM_CONFIG:
194 		metrics_stream_config(metrics_msg->data.stream_config);
195 		break;
196 	default:
197 		syslog(LOG_ERR, "Unknown metrics type %u",
198 		       metrics_msg->metrics_type);
199 		break;
200 	}
201 
202 }
203 
cras_server_metrics_init()204 int cras_server_metrics_init() {
205 	cras_main_message_add_handler(CRAS_MAIN_METRICS,
206 				      handle_metrics_message, NULL);
207 	return 0;
208 }
209