Skip to content

Commit a37e053

Browse files
m-ronnblomdavid-marchand
authored andcommitted
service: extend service function call statistics
Add two new per-service counters. RTE_SERVICE_ATTR_IDLE_CALL_COUNT tracks the number of service function invocations where no work was performed. RTE_SERVICE_ATTR_ERROR_CALL_COUNT tracks the number invocations resulting in an error. The semantics of RTE_SERVICE_ATTR_CALL_COUNT remains the same (i.e., counting all invocations, regardless of return value). The new statistics may be useful for both debugging and profiling (e.g., calculate the average per-call processing latency for non-idle service calls). Service core tests are extended to cover the new counters, and coverage for RTE_SERVICE_ATTR_CALL_COUNT is improved. The documentation for the CYCLES attributes are updated to reflect their actual semantics. Signed-off-by: Mattias Rönnblom <[email protected]> Acked-by: Chengwen Feng <[email protected]> Acked-by: Harry van Haaren <[email protected]>
1 parent bf0ff8d commit a37e053

File tree

4 files changed

+148
-33
lines changed

4 files changed

+148
-33
lines changed

app/test/test_service_cores.c

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
*/
44

55
#include <rte_common.h>
6+
#include <rte_cycles.h>
67
#include <rte_hexdump.h>
7-
#include <rte_mbuf.h>
88
#include <rte_malloc.h>
9+
#include <rte_mbuf.h>
910
#include <rte_memcpy.h>
10-
#include <rte_cycles.h>
11+
#include <rte_random.h>
1112

1213
#include <rte_service.h>
1314
#include <rte_service_component.h>
@@ -16,8 +17,10 @@
1617

1718
/* used as the service core ID */
1819
static uint32_t slcore_id;
19-
/* used as timestamp to detect if a service core is running */
20-
static uint64_t service_tick;
20+
/* track service call count */
21+
static uint64_t service_calls;
22+
static uint64_t service_idle_calls;
23+
static uint64_t service_error_calls;
2124
/* used as a flag to check if a function was run */
2225
static uint32_t service_remote_launch_flag;
2326

@@ -46,9 +49,21 @@ testsuite_teardown(void)
4649
static int32_t dummy_cb(void *args)
4750
{
4851
RTE_SET_USED(args);
49-
service_tick++;
52+
53+
service_calls++;
54+
55+
switch (rte_rand_max(3)) {
56+
case 0:
57+
return 0;
58+
case 1:
59+
service_idle_calls++;
60+
return -EAGAIN;
61+
default:
62+
service_error_calls++;
63+
return -ENOENT;
64+
}
65+
5066
rte_delay_ms(SERVICE_DELAY);
51-
return 0;
5267
}
5368

5469
static int32_t dummy_mt_unsafe_cb(void *args)
@@ -121,6 +136,10 @@ unregister_all(void)
121136
rte_service_lcore_reset_all();
122137
rte_eal_mp_wait_lcore();
123138

139+
service_calls = 0;
140+
service_idle_calls = 0;
141+
service_error_calls = 0;
142+
124143
return TEST_SUCCESS;
125144
}
126145

@@ -295,12 +314,19 @@ service_attr_get(void)
295314
"Valid attr_get() call didn't return success");
296315
TEST_ASSERT_EQUAL(0, attr_value,
297316
"attr_get() call didn't set correct cycles (zero)");
298-
/* check correct call count */
317+
/* check correct call counts */
299318
const int attr_calls = RTE_SERVICE_ATTR_CALL_COUNT;
300319
TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_calls, &attr_value),
301320
"Valid attr_get() call didn't return success");
302-
TEST_ASSERT_EQUAL(0, attr_value,
303-
"attr_get() call didn't get call count (zero)");
321+
TEST_ASSERT_EQUAL(0, attr_value, "Call count was not zero");
322+
const int attr_idle_calls = RTE_SERVICE_ATTR_IDLE_CALL_COUNT;
323+
TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_idle_calls, &attr_value),
324+
"Valid attr_get() call didn't return success");
325+
TEST_ASSERT_EQUAL(0, attr_value, "Idle call count was not zero");
326+
const int attr_error_calls = RTE_SERVICE_ATTR_ERROR_CALL_COUNT;
327+
TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_error_calls, &attr_value),
328+
"Valid attr_get() call didn't return success");
329+
TEST_ASSERT_EQUAL(0, attr_value, "Error call count was not zero");
304330

305331
/* Call service to increment cycle count */
306332
TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_id),
@@ -331,8 +357,13 @@ service_attr_get(void)
331357

332358
TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_calls, &attr_value),
333359
"Valid attr_get() call didn't return success");
334-
TEST_ASSERT_EQUAL(1, (attr_value > 0),
335-
"attr_get() call didn't get call count (zero)");
360+
TEST_ASSERT_EQUAL(service_calls, attr_value, "Unexpected call count");
361+
TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_idle_calls, &attr_value),
362+
"Valid attr_get() call didn't return success");
363+
TEST_ASSERT_EQUAL(service_idle_calls, attr_value, "Unexpected idle call count");
364+
TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_error_calls, &attr_value),
365+
"Valid attr_get() call didn't return success");
366+
TEST_ASSERT_EQUAL(service_error_calls, attr_value, "Unexpected error call count");
336367

337368
TEST_ASSERT_EQUAL(0, rte_service_attr_reset_all(id),
338369
"Valid attr_reset_all() return success");
@@ -341,11 +372,16 @@ service_attr_get(void)
341372
"Valid attr_get() call didn't return success");
342373
TEST_ASSERT_EQUAL(0, attr_value,
343374
"attr_get() call didn't set correct cycles (zero)");
344-
/* ensure call count > zero */
375+
/* ensure call counts are zero */
345376
TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_calls, &attr_value),
346377
"Valid attr_get() call didn't return success");
347-
TEST_ASSERT_EQUAL(0, (attr_value > 0),
348-
"attr_get() call didn't get call count (zero)");
378+
TEST_ASSERT_EQUAL(0, attr_value, "Call count was not reset");
379+
TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_idle_calls, &attr_value),
380+
"Valid attr_get() call didn't return success");
381+
TEST_ASSERT_EQUAL(0, attr_value, "Idle call count was not reset");
382+
TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_error_calls, &attr_value),
383+
"Valid attr_get() call didn't return success");
384+
TEST_ASSERT_EQUAL(0, attr_value, "Error call count was not reset");
349385

350386
return unregister_all();
351387
}
@@ -533,10 +569,10 @@ service_lcore_en_dis_able(void)
533569
static int
534570
service_lcore_running_check(void)
535571
{
536-
uint64_t tick = service_tick;
572+
uint64_t calls = service_calls;
537573
rte_delay_ms(SERVICE_DELAY * 100);
538-
/* if (tick != service_tick) we know the lcore as polled the service */
539-
return tick != service_tick;
574+
bool service_polled = calls != service_calls;
575+
return service_polled;
540576
}
541577

542578
static int

doc/guides/rel_notes/release_24_11.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ New Features
5555
Also, make sure to start the actual text at the margin.
5656
=======================================================
5757
58+
* **Extended service cores statistics.**
59+
60+
Two new per-service counters are added to the service cores framework.
61+
62+
* ``RTE_SERVICE_ATTR_IDLE_CALL_COUNT`` tracks the number of service function
63+
invocations where no actual work was performed.
64+
65+
* ``RTE_SERVICE_ATTR_ERROR_CALL_COUNT`` tracks the number invocations
66+
resulting in an error.
67+
68+
The new statistics are useful for debugging and profiling.
69+
5870

5971
Removed Items
6072
-------------

lib/eal/common/rte_service.c

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ struct __rte_cache_aligned rte_service_spec_impl {
5757

5858
struct service_stats {
5959
RTE_ATOMIC(uint64_t) calls;
60+
RTE_ATOMIC(uint64_t) idle_calls;
61+
RTE_ATOMIC(uint64_t) error_calls;
6062
RTE_ATOMIC(uint64_t) cycles;
6163
};
6264

@@ -369,6 +371,21 @@ rte_service_runstate_get(uint32_t id)
369371

370372
}
371373

374+
static void
375+
service_counter_add(RTE_ATOMIC(uint64_t) *counter, uint64_t operand)
376+
{
377+
/* The lcore service worker thread is the only writer, and
378+
* thus only a non-atomic load and an atomic store is needed,
379+
* and not the more expensive atomic add.
380+
*/
381+
uint64_t value;
382+
383+
value = rte_atomic_load_explicit(counter, rte_memory_order_relaxed);
384+
385+
rte_atomic_store_explicit(counter, value + operand,
386+
rte_memory_order_relaxed);
387+
}
388+
372389
static inline void
373390
service_runner_do_callback(struct rte_service_spec_impl *s,
374391
struct core_state *cs, uint32_t service_idx)
@@ -380,27 +397,23 @@ service_runner_do_callback(struct rte_service_spec_impl *s,
380397
uint64_t start = rte_rdtsc();
381398
int rc = s->spec.callback(userdata);
382399

383-
/* The lcore service worker thread is the only writer,
384-
* and thus only a non-atomic load and an atomic store
385-
* is needed, and not the more expensive atomic
386-
* add.
387-
*/
388400
struct service_stats *service_stats =
389401
&cs->service_stats[service_idx];
390402

403+
service_counter_add(&service_stats->calls, 1);
404+
405+
if (rc == -EAGAIN)
406+
service_counter_add(&service_stats->idle_calls, 1);
407+
else if (rc != 0)
408+
service_counter_add(&service_stats->error_calls, 1);
409+
391410
if (likely(rc != -EAGAIN)) {
392411
uint64_t end = rte_rdtsc();
393412
uint64_t cycles = end - start;
394413

395-
rte_atomic_store_explicit(&cs->cycles, cs->cycles + cycles,
396-
rte_memory_order_relaxed);
397-
rte_atomic_store_explicit(&service_stats->cycles,
398-
service_stats->cycles + cycles,
399-
rte_memory_order_relaxed);
414+
service_counter_add(&cs->cycles, cycles);
415+
service_counter_add(&service_stats->cycles, cycles);
400416
}
401-
402-
rte_atomic_store_explicit(&service_stats->calls,
403-
service_stats->calls + 1, rte_memory_order_relaxed);
404417
} else {
405418
s->spec.callback(userdata);
406419
}
@@ -867,6 +880,24 @@ lcore_attr_get_service_calls(uint32_t service_id, unsigned int lcore)
867880
rte_memory_order_relaxed);
868881
}
869882

883+
static uint64_t
884+
lcore_attr_get_service_idle_calls(uint32_t service_id, unsigned int lcore)
885+
{
886+
struct core_state *cs = &lcore_states[lcore];
887+
888+
return rte_atomic_load_explicit(&cs->service_stats[service_id].idle_calls,
889+
rte_memory_order_relaxed);
890+
}
891+
892+
static uint64_t
893+
lcore_attr_get_service_error_calls(uint32_t service_id, unsigned int lcore)
894+
{
895+
struct core_state *cs = &lcore_states[lcore];
896+
897+
return rte_atomic_load_explicit(&cs->service_stats[service_id].error_calls,
898+
rte_memory_order_relaxed);
899+
}
900+
870901
static uint64_t
871902
lcore_attr_get_service_cycles(uint32_t service_id, unsigned int lcore)
872903
{
@@ -899,6 +930,18 @@ attr_get_service_calls(uint32_t service_id)
899930
return attr_get(service_id, lcore_attr_get_service_calls);
900931
}
901932

933+
static uint64_t
934+
attr_get_service_idle_calls(uint32_t service_id)
935+
{
936+
return attr_get(service_id, lcore_attr_get_service_idle_calls);
937+
}
938+
939+
static uint64_t
940+
attr_get_service_error_calls(uint32_t service_id)
941+
{
942+
return attr_get(service_id, lcore_attr_get_service_error_calls);
943+
}
944+
902945
static uint64_t
903946
attr_get_service_cycles(uint32_t service_id)
904947
{
@@ -918,6 +961,12 @@ rte_service_attr_get(uint32_t id, uint32_t attr_id, uint64_t *attr_value)
918961
case RTE_SERVICE_ATTR_CALL_COUNT:
919962
*attr_value = attr_get_service_calls(id);
920963
return 0;
964+
case RTE_SERVICE_ATTR_IDLE_CALL_COUNT:
965+
*attr_value = attr_get_service_idle_calls(id);
966+
return 0;
967+
case RTE_SERVICE_ATTR_ERROR_CALL_COUNT:
968+
*attr_value = attr_get_service_error_calls(id);
969+
return 0;
921970
case RTE_SERVICE_ATTR_CYCLES:
922971
*attr_value = attr_get_service_cycles(id);
923972
return 0;

lib/eal/include/rte_service.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,15 +374,32 @@ int32_t rte_service_lcore_count_services(uint32_t lcore);
374374
int32_t rte_service_dump(FILE *f, uint32_t id);
375375

376376
/**
377-
* Returns the number of cycles that this service has consumed
377+
* Returns the number of cycles that this service has consumed. Only
378+
* cycles spent in non-idle calls (i.e., calls not returning -EAGAIN)
379+
* count.
378380
*/
379381
#define RTE_SERVICE_ATTR_CYCLES 0
380382

381383
/**
382-
* Returns the count of invocations of this service function
384+
* Returns the total number of invocations of this service function
385+
* (regardless of return value).
383386
*/
384387
#define RTE_SERVICE_ATTR_CALL_COUNT 1
385388

389+
/**
390+
* Returns the number of invocations of this service function where the
391+
* service reported having not performed any useful work (i.e.,
392+
* returned -EAGAIN).
393+
*/
394+
#define RTE_SERVICE_ATTR_IDLE_CALL_COUNT 2
395+
396+
/**
397+
* Returns the number of invocations of this service function where the
398+
* service reported an error (i.e., the return value was neither 0 nor
399+
* -EAGAIN).
400+
*/
401+
#define RTE_SERVICE_ATTR_ERROR_CALL_COUNT 3
402+
386403
/**
387404
* Get an attribute from a service.
388405
*
@@ -408,7 +425,8 @@ int32_t rte_service_attr_reset_all(uint32_t id);
408425

409426
/**
410427
* Returns the total number of cycles that the lcore has spent on
411-
* running services.
428+
* running services. Only non-idle calls (i.e., calls not returning
429+
* -EAGAIN) count toward this total.
412430
*/
413431
#define RTE_SERVICE_LCORE_ATTR_CYCLES 1
414432

0 commit comments

Comments
 (0)