NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
telemetry_diag_sample.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024 NVIDIA CORPORATION AND AFFILIATES. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are permitted
5  * provided that the following conditions are met:
6  * * Redistributions of source code must retain the above copyright notice, this list of
7  * conditions and the following disclaimer.
8  * * Redistributions in binary form must reproduce the above copyright notice, this list of
9  * conditions and the following disclaimer in the documentation and/or other materials
10  * provided with the distribution.
11  * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
12  * to endorse or promote products derived from this software without specific prior written
13  * permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21  * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  */
25 
26 #include <doca_error.h>
27 #include <doca_log.h>
28 #include <doca_dev.h>
29 #include <doca_telemetry_diag.h>
30 #include <errno.h>
31 #include <time.h>
32 #include <math.h>
33 #include <unistd.h>
34 
35 #include "common.h"
36 #include "telemetry_diag_sample.h"
37 
38 DOCA_LOG_REGISTER(TELEMETRY_DIAG::SAMPLE);
39 
40 #define SECS_TO_NSECS_CONVERSION pow(10, 9)
41 
43  struct doca_telemetry_diag *telemetry_diag_obj; /* Telemetry diag object*/
44  struct doca_dev *dev; /* Doca device*/
45  uint32_t num_data_ids;
46  uint8_t started; /* True if telemetry_diag struct was started*/
47  void *buf; /* Buf for the sampling output*/
48  FILE *output_file; /* Output file*/
49 };
50 
51 /*
52  * Verify params
53  *
54  * make sure all input params are valid and supported.
55  *
56  * @dev [in]: doca device
57  * @log_max_num_samples [in]: log max num of samples to be used
58  * @max_num_data_ids [in]: max num data IDs to be used
59  * @sync_mode [in]: sync mode to use
60  * @sample_mode [in]: sample mode to use
61  * @data_clear [in]: whether to use data_clear mode
62  * @data_timestamp_source [in]: data timestamp source to use
63  * @return: DOCA_SUCCESS on success, DOCA_ERROR_NOT_SUPPORTED if any of the params is not supported.
64  */
66  struct doca_dev *dev,
67  uint8_t log_max_num_samples,
68  uint32_t max_num_data_ids,
69  enum doca_telemetry_diag_sync_mode sync_mode,
70  enum doca_telemetry_diag_sample_mode sample_mode,
71  uint8_t data_clear,
72  enum doca_telemetry_diag_timestamp_source data_timestamp_source)
73 {
74  uint32_t cap_32_bit;
75  uint8_t cap_8_bit;
77 
78  struct doca_devinfo *devinfo = doca_dev_as_devinfo(dev);
79 
82  DOCA_LOG_ERR("Device does not support doca_telemetry_diag");
84  } else if (result != DOCA_SUCCESS) {
85  DOCA_LOG_ERR("Failed to query capability");
86  return result;
87  }
88 
90  if (result != DOCA_SUCCESS) {
91  DOCA_LOG_ERR("Failed to query capability");
92  return result;
93  } else if (log_max_num_samples > cap_8_bit) {
95  "Parameter log_max_num_samples is larger than supported cap: log_max_num_samples=%d, cap=%d",
96  log_max_num_samples,
97  cap_8_bit);
99  }
100 
102  if (result != DOCA_SUCCESS) {
103  DOCA_LOG_ERR("Failed to query capability");
104  return result;
105  } else if (max_num_data_ids > cap_32_bit) {
106  DOCA_LOG_ERR("Parameter max_num_data_ids is larger than supported cap: max_num_data_ids=%d, cap=%d",
107  max_num_data_ids,
108  cap_32_bit);
110  }
111 
112  if (sync_mode == DOCA_TELEMETRY_DIAG_SYNC_MODE_SYNC_START) {
114  if (result != DOCA_SUCCESS) {
115  DOCA_LOG_ERR("Failed to query capability");
116  return result;
117  } else if (!cap_8_bit) {
118  DOCA_LOG_ERR("Sync mode not supported");
120  }
121  }
122 
123  result = doca_telemetry_diag_cap_is_sample_mode_supported(devinfo, sample_mode, &cap_8_bit);
124  if (result != DOCA_SUCCESS) {
125  DOCA_LOG_ERR("Failed to query capability");
126  return result;
127  } else if (!cap_8_bit) {
128  DOCA_LOG_ERR("Sample mode not supported");
130  }
131 
132  if (!!data_clear) {
134  if (result != DOCA_SUCCESS) {
135  DOCA_LOG_ERR("Failed to query capability");
136  return result;
137  } else if (!cap_8_bit) {
138  DOCA_LOG_ERR("Data clear mode not supported");
140  }
141  }
142 
143  result = doca_telemetry_diag_cap_is_data_timestamp_source_supported(devinfo, data_timestamp_source, &cap_8_bit);
144  if (result != DOCA_SUCCESS) {
145  DOCA_LOG_ERR("Failed to query capability");
146  return result;
147  } else if (!cap_8_bit) {
148  DOCA_LOG_ERR("Timestamp source not supported");
150  }
151 
152  return DOCA_SUCCESS;
153 }
154 
155 /*
156  * Clean sample objects
157  *
158  * Closes and frees sample resources.
159  *
160  * @sample_objects [in]: sample objects to clean
161  * @return: DOCA_SUCCESS in case of success, DOCA_ERROR otherwise
162  */
164 {
166  int file_result = 0;
167 
168  if (sample_objects->buf != NULL) {
169  free(sample_objects->buf);
170  sample_objects->buf = NULL;
171  }
172 
173  if (sample_objects->telemetry_diag_obj != NULL) {
174  if (sample_objects->started) {
176  if (result != DOCA_SUCCESS) {
177  DOCA_LOG_WARN("Failed to stop telemetry_diag with error=%s",
179  return result;
180  }
181  }
183  if (result != DOCA_SUCCESS) {
184  DOCA_LOG_WARN("Failed to destroy telemetry_diag with error=%s", doca_error_get_name(result));
185  return result;
186  }
187  sample_objects->telemetry_diag_obj = NULL;
188  }
189 
190  if (sample_objects->dev != NULL) {
191  result = doca_dev_close(sample_objects->dev);
192  if (result != DOCA_SUCCESS) {
193  DOCA_LOG_WARN("Failed to close device with error=%s", doca_error_get_name(result));
194  return result;
195  }
196  sample_objects->dev = NULL;
197  }
198 
199  if (sample_objects->output_file != NULL) {
200  file_result = fclose(sample_objects->output_file);
201  if (file_result != 0) {
202  DOCA_LOG_WARN("Failed to close output file with errno=%s (%d)", strerror(errno), errno);
203  return DOCA_ERROR_UNEXPECTED;
204  }
205  sample_objects->output_file = NULL;
206  }
207  return DOCA_SUCCESS;
208 }
209 
210 /*
211  * set telemetry_diag properties
212  *
213  * @diag [in]: telemetry_diag context to set properties to
214  * @output_format [in]: output format to be used
215  * @sample_period [in]: sample period to be used
216  * @log_max_num_samples [in]: log max num of samples to be used
217  * @max_num_data_ids [in]: max num data IDs to be used
218  * @sync_mode [in]: sync mode to use
219  * @sample_mode [in]: sample mode to use
220  * @data_clear [in]: whether to use data_clear mode
221  * @data_timestamp_source [in]: data timestamp source to use
222  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise.
223  */
224 static doca_error_t telemetry_diag_sample_set_properties(struct doca_telemetry_diag *diag,
225  enum doca_telemetry_diag_output_format output_format,
226  uint64_t sample_period,
227  uint8_t log_max_num_samples,
228  uint32_t max_num_data_ids,
229  enum doca_telemetry_diag_sync_mode sync_mode,
230  enum doca_telemetry_diag_sample_mode sample_mode,
231  uint8_t data_clear,
232  enum doca_telemetry_diag_timestamp_source data_timestamp_source)
233 {
235 
236  result = doca_telemetry_diag_set_output_format(diag, output_format);
237  if (result != DOCA_SUCCESS) {
238  DOCA_LOG_ERR("Failed to set output_format with error=%s", doca_error_get_name(result));
239  return result;
240  }
241 
242  result = doca_telemetry_diag_set_sample_period(diag, sample_period);
243  if (result != DOCA_SUCCESS) {
244  DOCA_LOG_ERR("Failed to set sample_period with error=%s", doca_error_get_name(result));
245  return result;
246  }
247 
248  result = doca_telemetry_diag_set_log_max_num_samples(diag, log_max_num_samples);
249  if (result != DOCA_SUCCESS) {
250  DOCA_LOG_ERR("Failed to set log_max_num_samples with error=%s", doca_error_get_name(result));
251  return result;
252  }
253 
254  result = doca_telemetry_diag_set_max_num_data_ids(diag, max_num_data_ids);
255  if (result != DOCA_SUCCESS) {
256  DOCA_LOG_ERR("Failed to set max_num_data_ids with error=%s", doca_error_get_name(result));
257  return result;
258  }
259 
260  result = doca_telemetry_diag_set_sync_mode(diag, sync_mode);
261  if (result != DOCA_SUCCESS) {
262  DOCA_LOG_ERR("Failed to set sync_mode with error=%s", doca_error_get_name(result));
263  return result;
264  }
265 
266  result = doca_telemetry_diag_set_sample_mode(diag, sample_mode);
267  if (result != DOCA_SUCCESS) {
268  DOCA_LOG_ERR("Failed to set sample_mode with error=%s", doca_error_get_name(result));
269  return result;
270  }
271 
272  result = doca_telemetry_diag_set_data_clear(diag, data_clear);
273  if (result != DOCA_SUCCESS) {
274  DOCA_LOG_ERR("Failed to set sample_mode with error=%s", doca_error_get_name(result));
275  return result;
276  }
277 
278  result = doca_telemetry_diag_set_data_timestamp_source(diag, data_timestamp_source);
279  if (result != DOCA_SUCCESS) {
280  DOCA_LOG_ERR("Failed to set data_timestamp_source with error=%s", doca_error_get_name(result));
281  return result;
282  }
283 
284  return DOCA_SUCCESS;
285 }
286 
287 /*
288  * Calculate difference between two timespecs, in nanoseconds
289  *
290  *
291  * @start [in]: start of time period
292  * @end [in]: end of time period
293  * @return: difference between times, in nanoseconds
294  */
295 static inline uint64_t telemetry_diag_sample_time_diff_nsec(struct timespec start, struct timespec end)
296 {
297  return ((end.tv_nsec + (end.tv_sec - start.tv_sec) * SECS_TO_NSECS_CONVERSION) - start.tv_nsec);
298 }
299 
300 /*
301  * Initialize telemetry diag context object
302  *
303  * @sample_objects [in]: sample objects struct for the sample
304  * @data_ids_struct [in]: array of data_id_entry structures
305  * @num_data_ids [in]: the number of entries in the data_ids_struct
306  * @sample_period_ns [in]: sample period to be used
307  * @log_max_num_samples [in]: log max num of samples to be used
308  * @sample_mode [in]: sample mode to use
309  * @output_format [in]: output format to use
310  * @force_ownership [in]: force ownership when creating diag context
311  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise.
312  */
314  struct data_id_entry *data_ids_struct,
315  uint32_t num_data_ids,
316  uint64_t sample_period_ns,
317  uint8_t log_max_num_samples,
318  enum doca_telemetry_diag_sample_mode sample_mode,
319  enum doca_telemetry_diag_output_format output_format,
320  uint8_t force_ownership)
321 {
322  uint8_t data_clear = 0;
323  uint32_t max_num_data_ids = num_data_ids;
326 
327  doca_error_t result, teardown_result;
328  uint64_t counter_id_failure = 0;
329 
330  uint64_t data_ids[(size_t)num_data_ids];
331 
332  /* Check support for input arguments */
334  log_max_num_samples,
335  max_num_data_ids,
336  sync_mode,
337  sample_mode,
338  data_clear,
339  timestamp_source);
340  if (result != DOCA_SUCCESS) {
341  DOCA_LOG_ERR("Failed capability checks with error=%s", doca_error_get_name(result));
342  return result;
343  }
344 
345  /* Create context and set properties */
346  result = doca_telemetry_diag_create(sample_objects->dev, force_ownership, &sample_objects->telemetry_diag_obj);
347  if (result != DOCA_SUCCESS) {
348  DOCA_LOG_ERR("Failed to create telemetry diag object with error=%s", doca_error_get_name(result));
349  goto teardown_init;
350  }
351 
353  output_format,
354  sample_period_ns,
355  log_max_num_samples,
356  max_num_data_ids,
357  sync_mode,
358  sample_mode,
359  data_clear,
360  timestamp_source);
361  if (result != DOCA_SUCCESS) {
362  DOCA_LOG_ERR("Failed to set properties with error=%s", doca_error_get_name(result));
363  goto teardown_init;
364  }
365 
366  sample_objects->num_data_ids = num_data_ids;
367 
369  if (result != DOCA_SUCCESS) {
370  DOCA_LOG_ERR("Failed to apply config with error=%s", doca_error_get_name(result));
371  goto teardown_init;
372  }
373 
374  for (uint32_t i = 0; i < num_data_ids; i++) {
375  data_ids[i] = data_ids_struct[i].data_id;
376  }
377 
379  data_ids,
380  num_data_ids,
381  &counter_id_failure);
382  if (result != DOCA_SUCCESS) {
383  DOCA_LOG_ERR("Failed to apply counters with error=%s, counter_id_failure=%ld",
385  counter_id_failure);
386  goto teardown_init;
387  }
388 
389  return DOCA_SUCCESS;
390 
391 teardown_init:
392  teardown_result = telemetry_diag_sample_cleanup(sample_objects);
393  if (teardown_result != DOCA_SUCCESS) {
394  DOCA_LOG_ERR("Teardown failed with error=%s", doca_error_get_name(teardown_result));
395  }
396  return result;
397 }
398 
399 /*
400  * Process and write the results of a single query to the output file when using output format 1
401  *
402  * @sample_objects [in]: sample objects struct for the sample
403  * @num_actual_samples [in]: the number of samples that were returned from the query
404  * @size_of_sample [in]: size of a single sample in the result buf
405  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise.
406  */
408  struct telemetry_diag_sample_objects *sample_objects,
409  uint32_t num_actual_samples,
410  uint32_t size_of_sample)
411 {
412  uint32_t latest_timestamp_h;
413  int write_result = 0;
414 
415  struct doca_telemetry_diag_data_sample_format_1 *current_sample =
416  (struct doca_telemetry_diag_data_sample_format_1 *)sample_objects->buf;
417  for (uint32_t sample_index = 0; sample_index < num_actual_samples; sample_index++) {
418  /* If the end timestamp lower bits is smaller than the start timestamp lower bits, it means the upper
419  * bits need to be advanced*/
420  latest_timestamp_h = current_sample->earliest_data_timestamp_h;
421  if (current_sample->latest_data_timestamp_l < current_sample->earliest_data_timestamp_l)
422  latest_timestamp_h++;
423 
424  /* Write counters to csv file. The below timestamp print is only valid for RTC timestamp format*/
425  write_result = fprintf(sample_objects->output_file,
426  "\n%u,%u.%u,%u.%u",
427  current_sample->sample_id,
428  current_sample->earliest_data_timestamp_h,
429  current_sample->earliest_data_timestamp_l,
430  latest_timestamp_h,
431  current_sample->latest_data_timestamp_l);
432  if (write_result < 0) {
433  DOCA_LOG_ERR("Failed to write to output file with errno=%s (%d)", strerror(errno), errno);
434  return DOCA_ERROR_IO_FAILED;
435  }
436 
437  for (uint32_t j = 0; j < sample_objects->num_data_ids; j++) {
438  write_result = fprintf(sample_objects->output_file, ", %lu", current_sample->data_value[j]);
439  if (write_result < 0) {
440  DOCA_LOG_ERR("Failed to write to output file with errno=%s (%d)",
441  strerror(errno),
442  errno);
443  return DOCA_ERROR_IO_FAILED;
444  }
445  }
446 
447  /* Update the pointer to the next sample location */
448  current_sample =
449  (doca_telemetry_diag_data_sample_format_1 *)((uint8_t *)current_sample + size_of_sample);
450  }
451  return DOCA_SUCCESS;
452 }
453 
454 /*
455  * Process and write the results of a single query to the output file when using output format 2
456  *
457  * @sample_objects [in]: sample objects struct for the sample
458  * @num_actual_samples [in]: the number of samples that were returned from the query
459  * @size_of_sample [in]: size of a single sample in the result buf
460  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise.
461  */
463  struct telemetry_diag_sample_objects *sample_objects,
464  uint32_t num_actual_samples,
465  uint32_t size_of_sample)
466 {
467  uint32_t latest_timestamp_h;
468  int write_result = 0;
469 
470  struct doca_telemetry_diag_data_sample_format_2 *current_sample =
471  (struct doca_telemetry_diag_data_sample_format_2 *)sample_objects->buf;
472  for (uint32_t sample_index = 0; sample_index < num_actual_samples; sample_index++) {
473  /* If the end timestamp lower bits is smaller than the start timestamp lower bits, it means the upper
474  * bits need to be advanced*/
475  latest_timestamp_h = current_sample->earliest_data_timestamp_h;
476  if (current_sample->latest_data_timestamp_l < current_sample->earliest_data_timestamp_l)
477  latest_timestamp_h++;
478 
479  /* Write counters to csv file. The below timestamp print is only valid for RTC timestamp format*/
480  write_result = fprintf(sample_objects->output_file,
481  "\n%u,%u.%u,%u.%u",
482  current_sample->sample_id,
483  current_sample->earliest_data_timestamp_h,
484  current_sample->earliest_data_timestamp_l,
485  latest_timestamp_h,
486  current_sample->latest_data_timestamp_l);
487  if (write_result < 0) {
488  DOCA_LOG_ERR("Failed to write to output file with errno=%s (%d)", strerror(errno), errno);
489  return DOCA_ERROR_IO_FAILED;
490  }
491 
492  for (uint32_t j = 0; j < sample_objects->num_data_ids; j++) {
493  write_result = fprintf(sample_objects->output_file, ", %u", current_sample->data_value[j]);
494  if (write_result < 0) {
495  DOCA_LOG_ERR("Failed to write to output file with errno=%s (%d)",
496  strerror(errno),
497  errno);
498  return DOCA_ERROR_IO_FAILED;
499  }
500  }
501 
502  /* Update the pointer to the next sample location */
503  current_sample =
504  (doca_telemetry_diag_data_sample_format_2 *)((uint8_t *)current_sample + size_of_sample);
505  }
506  return DOCA_SUCCESS;
507 }
508 
509 /*
510  * Process and write the results of a single query to the output file
511  *
512  * @sample_objects [in]: sample objects struct for the sample
513  * @num_actual_samples [in]: the number of samples that were returned from the query
514  * @size_of_sample [in]: size of a single sample in the result buf
515  * @output_format [in]: the output format used by the sample
516  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise.
517  */
519  uint32_t num_actual_samples,
520  uint32_t size_of_sample,
521  enum doca_telemetry_diag_output_format output_format)
522 {
523  switch (output_format) {
525  DOCA_LOG_ERR("Failed to write output: format not supported in sample");
528  return telemetry_diag_sample_write_sample_format_1(sample_objects, num_actual_samples, size_of_sample);
530  return telemetry_diag_sample_write_sample_format_2(sample_objects, num_actual_samples, size_of_sample);
531  default:
532  DOCA_LOG_ERR("Output format %d not recognized", output_format);
534  }
535 }
536 
537 /*
538  * Run the main loop for query counters in repetitive sample mode
539  *
540  * @sample_objects [in]: sample objects struct for the sample
541  * @max_num_samples_per_read [in]: max number of samples per read
542  * @total_run_time_nsec [in]: the total run time for the query loop
543  * @size_of_sample [in]: size of a single sample in the result buf
544  * @poll_interval [in]: Average time between calls to read samples
545  * @output_format [in]: the output format to use
546  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise.
547  */
549  struct telemetry_diag_sample_objects *sample_objects,
550  uint32_t max_num_samples_per_read,
551  uint64_t total_run_time_nsec,
552  uint32_t size_of_sample,
553  uint64_t poll_interval,
554  enum doca_telemetry_diag_output_format output_format)
555 {
556  uint64_t process_period_nsec;
557  struct timespec t_period_start = {0, 0}; /* Will be used per sample */
558  struct timespec t_polling_start = {0, 0}, t_polling_current = {0, 0}; /* Will be used for overall runtime */
559  uint32_t num_actual_samples = 0;
560 
562 
563  if (clock_gettime(CLOCK_REALTIME, &t_polling_start) < 0) {
564  DOCA_LOG_ERR("Failed to get time with errno=%s (%d)", strerror(errno), errno);
565  }
566  t_polling_current = t_polling_start;
567 
568  while (telemetry_diag_sample_time_diff_nsec(t_polling_start, t_polling_current) < total_run_time_nsec) {
570  sample_objects->buf,
571  max_num_samples_per_read,
572  &num_actual_samples);
573  if (result == DOCA_ERROR_SKIPPED) {
574  DOCA_LOG_INFO("One or more samples were skipped");
575  } else if (result != DOCA_SUCCESS) {
576  DOCA_LOG_ERR("Failed to query counters with error=%s", doca_error_get_name(result));
577  return result;
578  }
579 
580  /* Start counting processing time */
581  if (clock_gettime(CLOCK_REALTIME, &t_period_start) < 0) {
582  DOCA_LOG_ERR("Failed to get time with errno=%s (%d)", strerror(errno), errno);
583  }
585  num_actual_samples,
586  size_of_sample,
587  output_format);
588  if (result != DOCA_SUCCESS) {
589  DOCA_LOG_ERR("Failed to process samples with error=%s", doca_error_get_name(result));
590  return result;
591  }
592 
593  if (clock_gettime(CLOCK_REALTIME, &t_polling_current) < 0) {
594  DOCA_LOG_ERR("Failed to get time with errno=%s (%d)", strerror(errno), errno);
595  }
596 
597  process_period_nsec = telemetry_diag_sample_time_diff_nsec(t_period_start, t_polling_current);
598  /* If we got the max num of samples when querying, it is possible there are more samples to be polled,
599  * so sleep only if we got less samples from max. */
600  if ((num_actual_samples < max_num_samples_per_read) && poll_interval > process_period_nsec)
601  usleep((poll_interval - process_period_nsec) / 1000); /* Convert nseconds to useconds*/
602  }
603  return DOCA_SUCCESS;
604 }
605 
606 /*
607  * Run the main loop for query counters until num_samples_to_read samples are read
608  *
609  * @sample_objects [in]: sample objects struct for the sample
610  * @num_samples_to_read [in]: the total number of samples to read
611  * @max_num_samples_per_read [in]: max number of samples per read
612  * @size_of_sample [in]: size of a single sample in the result buf
613  * @output_format [in]: the output format to use
614  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise.
615  */
617  struct telemetry_diag_sample_objects *sample_objects,
618  uint32_t num_samples_to_read,
619  uint32_t max_num_samples_per_read,
620  uint32_t size_of_sample,
621  enum doca_telemetry_diag_output_format output_format)
622 {
623  uint32_t num_actual_samples = 0;
624  uint32_t total_num_samples_read = 0;
625  uint32_t num_samples_to_read_in_query = max_num_samples_per_read;
626 
628 
629  while (total_num_samples_read < num_samples_to_read) {
630  if (num_samples_to_read_in_query > (num_samples_to_read - total_num_samples_read))
631  num_samples_to_read_in_query = (num_samples_to_read - total_num_samples_read);
632 
634  sample_objects->buf,
635  num_samples_to_read_in_query,
636  &num_actual_samples);
637  if (result != DOCA_SUCCESS) {
638  DOCA_LOG_ERR("Failed to query counters with error=%s", doca_error_get_name(result));
639  return result;
640  }
641 
643  num_actual_samples,
644  size_of_sample,
645  output_format);
646  if (result != DOCA_SUCCESS) {
647  DOCA_LOG_ERR("Failed to process samples with error=%s", doca_error_get_name(result));
648  return result;
649  }
650 
651  total_num_samples_read += num_actual_samples;
652  }
653  return DOCA_SUCCESS;
654 }
655 
657 {
658  doca_error_t result = DOCA_SUCCESS, teardown_result = DOCA_SUCCESS;
659  struct telemetry_diag_sample_objects sample_objects = {0};
660 
661  uint32_t size_of_sample;
662  uint32_t buf_size;
663 
664  uint64_t actual_sample_period;
665  uint64_t poll_interval;
666  uint64_t total_run_time_nsec = (uint64_t)cfg->run_time * SECS_TO_NSECS_CONVERSION; /* convert total poll
667  * time to nsec
668  */
669 
670  DOCA_LOG_DBG("Started doca_telemetry_diag sample with the following parameters: ");
671  DOCA_LOG_DBG(" pci_addr='%s'", cfg->pci_addr);
672  DOCA_LOG_DBG(" sample_run_time=%u", cfg->run_time);
673  DOCA_LOG_DBG(" output='%s'", cfg->output_path);
674  DOCA_LOG_DBG(" sample_period=%lu", cfg->sample_period);
675  DOCA_LOG_DBG(" log_num_samples=%u", cfg->log_max_num_samples);
676  DOCA_LOG_DBG(" max_samples_per_read=%u", cfg->max_num_samples_per_read);
677  DOCA_LOG_DBG(" sample_mode=%u", cfg->sample_mode);
678  DOCA_LOG_DBG(" output_format=%u", cfg->output_format);
679  DOCA_LOG_DBG(" force_ownership=%u", cfg->force_ownership);
680  DOCA_LOG_DBG(" data_ids='%s'", cfg->data_ids_input_path);
681  DOCA_LOG_DBG(" num_data_id=%u", cfg->num_data_ids);
682  for (uint32_t i = 0; i < cfg->num_data_ids; i++) {
683  DOCA_LOG_DBG(" entry %u: data_id=%llx, name='%s'",
684  i,
685  (unsigned long long int)cfg->data_ids_struct[i].data_id,
686  cfg->data_ids_struct[i].name);
687  }
688 
689  if (cfg->output_format == DOCA_TELEMETRY_DIAG_OUTPUT_FORMAT_0) {
690  DOCA_LOG_ERR("Output format %u is currently not supported by the sample", cfg->output_format);
692  }
693 
694  /* Open DOCA device based on the given PCI address */
695  result = open_doca_device_with_pci(cfg->pci_addr, NULL, &sample_objects.dev);
696  if (result != DOCA_SUCCESS) {
697  DOCA_LOG_ERR("Failed to open device with error=%s", doca_error_get_name(result));
698  }
699 
700  result = telemetry_diag_sample_context_init(&sample_objects,
701  cfg->data_ids_struct,
702  cfg->num_data_ids,
703  cfg->sample_period,
704  cfg->log_max_num_samples,
705  cfg->sample_mode,
706  cfg->output_format,
707  cfg->force_ownership);
708  if (result != DOCA_SUCCESS) {
709  DOCA_LOG_ERR("Failed to init sample objects with error=%s", doca_error_get_name(result));
710  goto teardown;
711  }
712 
713  sample_objects.output_file = fopen(cfg->output_path, "wr");
714  if (sample_objects.output_file == NULL) {
715  DOCA_LOG_ERR("Failed to open output file \"%s\" with errno=%s (%d)",
716  cfg->output_path,
717  strerror(errno),
718  errno);
720  goto teardown;
721  }
722 
723  /* Write first line of CSV output file*/
724  fprintf(sample_objects.output_file, "sample_id, sample_time_start, sample_time_end");
725  for (uint32_t i = 0; i < cfg->num_data_ids; i++) {
726  fprintf(sample_objects.output_file, ", %s", cfg->data_ids_struct[i].name);
727  }
728 
730  if (result != DOCA_SUCCESS) {
731  DOCA_LOG_ERR("Failed to start telemetry_diag with error=%s", doca_error_get_name(result));
732  goto teardown;
733  }
734  sample_objects.started = 1;
735 
736  result = doca_telemetry_diag_get_sample_size(sample_objects.telemetry_diag_obj, &size_of_sample);
737  if (result != DOCA_SUCCESS) {
738  DOCA_LOG_ERR("Failed to get sample size with error=%s", doca_error_get_name(result));
739  goto teardown;
740  }
741 
742  buf_size = size_of_sample * cfg->max_num_samples_per_read;
743  sample_objects.buf = malloc(buf_size);
744  if (sample_objects.buf == NULL) {
745  DOCA_LOG_ERR("Failed to allocate output buffer");
747  goto teardown;
748  }
749 
750  /* Value may differ if the device cannot support the requested sample period */
751  result = doca_telemetry_diag_get_sample_period(sample_objects.telemetry_diag_obj, &actual_sample_period);
752  if (result != DOCA_SUCCESS) {
753  DOCA_LOG_ERR("Failed to get sample period with error=%s", doca_error_get_name(result));
754  goto teardown;
755  }
756 
757  switch ((cfg->sample_mode)) {
759  /* Sleep for the time it takes to fill the whole buffer, then query the results */
760  usleep((actual_sample_period * (1U << cfg->log_max_num_samples)) / 1000); /* Convert nseconds to
761  useconds*/
762  /* Fallthrough */
765  (1U << cfg->log_max_num_samples),
766  cfg->max_num_samples_per_read,
767  size_of_sample,
768  cfg->output_format);
769  break;
771  poll_interval = actual_sample_period * (cfg->max_num_samples_per_read - 1); /* Average time between
772  calls to read samples. */
774  cfg->max_num_samples_per_read,
775  total_run_time_nsec,
776  size_of_sample,
777  poll_interval,
778  cfg->output_format);
779  break;
780  default:
781  DOCA_LOG_ERR("Failed to run query counters: unknown sample mode %d", cfg->sample_mode);
782  break;
783  }
784 
785  if (result != DOCA_SUCCESS) {
786  DOCA_LOG_ERR("Failed to run query counters with error=%s", doca_error_get_name(result));
787  goto teardown;
788  }
789 
790 teardown:
791  teardown_result = telemetry_diag_sample_cleanup(&sample_objects);
792  if (teardown_result != DOCA_SUCCESS) {
793  DOCA_LOG_ERR("Teardown failed with error=%s", doca_error_get_name(teardown_result));
794  DOCA_ERROR_PROPAGATE(result, teardown_result);
795  }
796  return result;
797 }
#define NULL
Definition: __stddef_null.h:26
__SIZE_TYPE__ size_t
int32_t result
static doca_error_t open_doca_device_with_pci(const char *pcie_value, struct doca_dev **retval)
Definition: device.c:43
DOCA_STABLE struct doca_devinfo * doca_dev_as_devinfo(const struct doca_dev *dev)
Get local device info from device. This should be useful when wanting to query information about devi...
DOCA_STABLE doca_error_t doca_dev_close(struct doca_dev *dev)
Destroy allocated local device instance.
#define DOCA_ERROR_PROPAGATE(r, t)
Save the first encountered doca_error_t.
Definition: doca_error.h:83
enum doca_error doca_error_t
DOCA API return codes.
DOCA_STABLE const char * doca_error_get_name(doca_error_t error)
Returns the string representation of an error code name.
@ DOCA_ERROR_UNEXPECTED
Definition: doca_error.h:60
@ DOCA_ERROR_NOT_SUPPORTED
Definition: doca_error.h:42
@ DOCA_ERROR_SKIPPED
Definition: doca_error.h:68
@ DOCA_ERROR_IO_FAILED
Definition: doca_error.h:55
@ DOCA_SUCCESS
Definition: doca_error.h:38
@ DOCA_ERROR_NO_MEMORY
Definition: doca_error.h:45
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
Definition: doca_log.h:466
#define DOCA_LOG_WARN(format,...)
Generates a WARNING application log message.
Definition: doca_log.h:476
#define DOCA_LOG_INFO(format,...)
Generates an INFO application log message.
Definition: doca_log.h:486
#define DOCA_LOG_DBG(format,...)
Generates a DEBUG application log message.
Definition: doca_log.h:496
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_destroy(struct doca_telemetry_diag *diag)
Destroy doca_telemetry_diag previously created by doca_telemetry_diag_create().
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_create(struct doca_dev *dev, uint8_t force_ownership, struct doca_telemetry_diag **diag)
Create a DOCA Telemetry Diagnostics instance.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_apply_config(struct doca_telemetry_diag *diag)
Apply device configuration.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_cap_is_data_timestamp_source_supported(const struct doca_devinfo *devinfo, enum doca_telemetry_diag_timestamp_source data_timestamp_source, uint8_t *timestamp_source_supported)
Check if given device supports a given data timestamp source.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_stop(struct doca_telemetry_diag *diag)
Stop device sampling.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_cap_get_log_max_num_samples(const struct doca_devinfo *devinfo, uint8_t *log_max_num_samples)
Get the maximal num (in log base 2) of samples that is supported by a given device.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_get_sample_period(struct doca_telemetry_diag *diag, uint64_t *sample_period)
Get sample period.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_get_sample_size(struct doca_telemetry_diag *diag, uint32_t *sample_size)
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_set_sample_period(struct doca_telemetry_diag *diag, uint64_t sample_period)
Set sample period.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_set_data_clear(struct doca_telemetry_diag *diag, uint8_t data_clear)
Set data clear.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_cap_is_supported(const struct doca_devinfo *devinfo)
Check if given device is capable of executing telemetry diagnostics operations.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_set_data_timestamp_source(struct doca_telemetry_diag *diag, enum doca_telemetry_diag_timestamp_source data_timestamp_source)
Set data timestamp source.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_start(struct doca_telemetry_diag *diag)
Start device sampling - trigger device to collect metrics.
doca_telemetry_diag_timestamp_source
description of the timestamp source of the sample
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_cap_get_max_num_data_ids(const struct doca_devinfo *devinfo, uint32_t *max_num_data_ids)
Get the maximal num of data IDs that is supported by a given device.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_cap_is_sync_start_supported(const struct doca_devinfo *devinfo, uint8_t *sync_start)
Check if given device supports sync start.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_cap_is_sample_mode_supported(const struct doca_devinfo *devinfo, enum doca_telemetry_diag_sample_mode sample_mode, uint8_t *sample_mode_supported)
Check if given device supports a given sample mode.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_set_max_num_data_ids(struct doca_telemetry_diag *diag, uint32_t max_num_data_ids)
Set max num of data IDs.
doca_telemetry_diag_sample_mode
description of data sampling mode
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_apply_counters_list_by_id(struct doca_telemetry_diag *diag, const uint64_t *data_ids, uint32_t num_data_ids, uint64_t *counter_id_failure)
Apply the counters, by their data ID, to be queried.
doca_telemetry_diag_sync_mode
Synchronization mode of data sampling.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_query_counters(struct doca_telemetry_diag *diag, void *buf, uint32_t max_samples_to_read, uint32_t *num_valid_samples)
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_set_log_max_num_samples(struct doca_telemetry_diag *diag, uint8_t log_max_num_samples)
Set log max of samples.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_cap_is_data_clear_supported(const struct doca_devinfo *devinfo, uint8_t *data_clear)
Check if given device supports data clear.
doca_telemetry_diag_output_format
Defines the layout of the diagnostic data output:
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_set_sync_mode(struct doca_telemetry_diag *diag, enum doca_telemetry_diag_sync_mode sync_mode)
Set synchronization mode.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_set_output_format(struct doca_telemetry_diag *diag, enum doca_telemetry_diag_output_format output_format)
Set output format.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_diag_set_sample_mode(struct doca_telemetry_diag *diag, enum doca_telemetry_diag_sample_mode sample_mode)
Set sampling mode.
@ DOCA_TELEMETRY_DIAG_TIMESTAMP_SOURCE_RTC
@ DOCA_TELEMETRY_DIAG_SAMPLE_MODE_ON_DEMAND
@ DOCA_TELEMETRY_DIAG_SAMPLE_MODE_SINGLE
@ DOCA_TELEMETRY_DIAG_SAMPLE_MODE_REPETITIVE
@ DOCA_TELEMETRY_DIAG_SYNC_MODE_SYNC_START
@ DOCA_TELEMETRY_DIAG_SYNC_MODE_NO_SYNC
@ DOCA_TELEMETRY_DIAG_OUTPUT_FORMAT_2
@ DOCA_TELEMETRY_DIAG_OUTPUT_FORMAT_0
@ DOCA_TELEMETRY_DIAG_OUTPUT_FORMAT_1
const struct ip_frag_config * cfg
Definition: ip_frag_dp.c:0
uint64_t data_id
struct doca_telemetry_diag * telemetry_diag_obj
static doca_error_t telemetry_diag_sample_run_query_counters_by_max_samples(struct telemetry_diag_sample_objects *sample_objects, uint32_t num_samples_to_read, uint32_t max_num_samples_per_read, uint32_t size_of_sample, enum doca_telemetry_diag_output_format output_format)
static doca_error_t telemetry_diag_sample_run_query_counters_repetitive(struct telemetry_diag_sample_objects *sample_objects, uint32_t max_num_samples_per_read, uint64_t total_run_time_nsec, uint32_t size_of_sample, uint64_t poll_interval, enum doca_telemetry_diag_output_format output_format)
static doca_error_t telemetry_diag_sample_write_output(struct telemetry_diag_sample_objects *sample_objects, uint32_t num_actual_samples, uint32_t size_of_sample, enum doca_telemetry_diag_output_format output_format)
static doca_error_t telemetry_diag_sample_context_init(struct telemetry_diag_sample_objects *sample_objects, struct data_id_entry *data_ids_struct, uint32_t num_data_ids, uint64_t sample_period_ns, uint8_t log_max_num_samples, enum doca_telemetry_diag_sample_mode sample_mode, enum doca_telemetry_diag_output_format output_format, uint8_t force_ownership)
static doca_error_t telemetry_diag_sample_cleanup(struct telemetry_diag_sample_objects *sample_objects)
static doca_error_t telemetry_diag_sample_set_properties(struct doca_telemetry_diag *diag, enum doca_telemetry_diag_output_format output_format, uint64_t sample_period, uint8_t log_max_num_samples, uint32_t max_num_data_ids, enum doca_telemetry_diag_sync_mode sync_mode, enum doca_telemetry_diag_sample_mode sample_mode, uint8_t data_clear, enum doca_telemetry_diag_timestamp_source data_timestamp_source)
doca_error_t telemetry_diag_sample_run(const struct telemetry_diag_sample_cfg *cfg)
DOCA_LOG_REGISTER(TELEMETRY_DIAG::SAMPLE)
static uint64_t telemetry_diag_sample_time_diff_nsec(struct timespec start, struct timespec end)
static doca_error_t telemetry_diag_sample_check_capabilities(struct doca_dev *dev, uint8_t log_max_num_samples, uint32_t max_num_data_ids, enum doca_telemetry_diag_sync_mode sync_mode, enum doca_telemetry_diag_sample_mode sample_mode, uint8_t data_clear, enum doca_telemetry_diag_timestamp_source data_timestamp_source)
#define SECS_TO_NSECS_CONVERSION
static doca_error_t telemetry_diag_sample_write_sample_format_1(struct telemetry_diag_sample_objects *sample_objects, uint32_t num_actual_samples, uint32_t size_of_sample)
static doca_error_t telemetry_diag_sample_write_sample_format_2(struct telemetry_diag_sample_objects *sample_objects, uint32_t num_actual_samples, uint32_t size_of_sample)