/* Perform a sanity test of the distributor with a large number of packets, * where we allocate a new set of mbufs for each burst. The workers then * free the mbufs. This ensures that we don't have any packet leaks in the * library. */ static int sanity_test_with_mbuf_alloc(struct rte_distributor *d, struct rte_mempool *p) { unsigned i; struct rte_mbuf *bufs[BURST]; printf("=== Sanity test with mbuf alloc/free ===\n"); clear_packet_count(); for (i = 0; i < ((1<<ITER_POWER)); i += BURST) { unsigned j; while (rte_mempool_get_bulk(p, (void *)bufs, BURST) < 0) rte_distributor_process(d, NULL, 0); for (j = 0; j < BURST; j++) { bufs[j]->pkt.hash.rss = (i+j) << 1; bufs[j]->refcnt = 1; } rte_distributor_process(d, bufs, BURST); } rte_distributor_flush(d); if (total_packet_count() < (1<<ITER_POWER)) { printf("Line %u: Packet count is incorrect, %u, expected %u\n", __LINE__, total_packet_count(), (1<<ITER_POWER)); return -1; } printf("Sanity test with mbuf alloc/free passed\n\n"); return 0; }
/* Perform a sanity test of the distributor with a large number of packets, * where we allocate a new set of mbufs for each burst. The workers then * free the mbufs. This ensures that we don't have any packet leaks in the * library. */ static int sanity_test_with_worker_shutdown(struct rte_distributor *d, struct rte_mempool *p) { struct rte_mbuf *bufs[BURST]; unsigned i; printf("=== Sanity test of worker shutdown ===\n"); clear_packet_count(); if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { printf("line %d: Error getting mbufs from pool\n", __LINE__); return -1; } /* now set all hash values in all buffers to zero, so all pkts go to the * one worker thread */ for (i = 0; i < BURST; i++) bufs[i]->pkt.hash.rss = 0; rte_distributor_process(d, bufs, BURST); /* at this point, we will have processed some packets and have a full * backlog for the other ones at worker 0. */ /* get more buffers to queue up, again setting them to the same flow */ if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { printf("line %d: Error getting mbufs from pool\n", __LINE__); return -1; } for (i = 0; i < BURST; i++) bufs[i]->pkt.hash.rss = 0; /* get worker zero to quit */ zero_quit = 1; rte_distributor_process(d, bufs, BURST); /* flush the distributor */ rte_distributor_flush(d); if (total_packet_count() != BURST * 2) { printf("Line %d: Error, not all packets flushed. " "Expected %u, got %u\n", __LINE__, BURST * 2, total_packet_count()); return -1; } for (i = 0; i < rte_lcore_count() - 1; i++) printf("Worker %u handled %u packets\n", i, worker_stats[i].handled_packets); printf("Sanity test with worker shutdown passed\n\n"); return 0; }
/* Test that the flush function is able to move packets between workers when * one worker shuts down.. */ static int test_flush_with_worker_shutdown(struct worker_params *wp, struct rte_mempool *p) { struct rte_distributor *d = wp->dist; struct rte_mbuf *bufs[BURST]; unsigned i; printf("=== Test flush fn with worker shutdown (%s) ===\n", wp->name); clear_packet_count(); if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { printf("line %d: Error getting mbufs from pool\n", __LINE__); return -1; } /* now set all hash values in all buffers to zero, so all pkts go to the * one worker thread */ for (i = 0; i < BURST; i++) bufs[i]->hash.usr = 0; rte_distributor_process(d, bufs, BURST); /* at this point, we will have processed some packets and have a full * backlog for the other ones at worker 0. */ /* get worker zero to quit */ zero_quit = 1; /* flush the distributor */ rte_distributor_flush(d); rte_delay_us(10000); zero_quit = 0; for (i = 0; i < rte_lcore_count() - 1; i++) printf("Worker %u handled %u packets\n", i, worker_stats[i].handled_packets); if (total_packet_count() != BURST) { printf("Line %d: Error, not all packets flushed. " "Expected %u, got %u\n", __LINE__, BURST, total_packet_count()); return -1; } printf("Flush test with worker shutdown passed\n\n"); return 0; }
/* * This basic performance test just repeatedly sends in 32 packets at a time * to the distributor and verifies at the end that we got them all in the worker * threads and finally how long per packet the processing took. */ static inline int perf_test(struct rte_distributor *d, struct rte_mempool *p) { unsigned int i; uint64_t start, end; struct rte_mbuf *bufs[BURST]; clear_packet_count(); if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { printf("Error getting mbufs from pool\n"); return -1; } /* ensure we have different hash value for each pkt */ for (i = 0; i < BURST; i++) bufs[i]->hash.usr = i; start = rte_rdtsc(); for (i = 0; i < (1<<ITER_POWER); i++) rte_distributor_process(d, bufs, BURST); end = rte_rdtsc(); do { usleep(100); rte_distributor_process(d, NULL, 0); } while (total_packet_count() < (BURST << ITER_POWER)); rte_distributor_clear_returns(d); printf("Time per burst: %"PRIu64"\n", (end - start) >> ITER_POWER); printf("Time per packet: %"PRIu64"\n\n", ((end - start) >> ITER_POWER)/BURST); rte_mempool_put_bulk(p, (void *)bufs, BURST); for (i = 0; i < rte_lcore_count() - 1; i++) printf("Worker %u handled %u packets\n", i, worker_stats[i].handled_packets); printf("Total packets: %u (%x)\n", total_packet_count(), total_packet_count()); printf("=== Perf test done ===\n\n"); return 0; }
/* Perform a sanity test of the distributor with a large number of packets, * where we allocate a new set of mbufs for each burst. The workers then * free the mbufs. This ensures that we don't have any packet leaks in the * library. */ static int sanity_test_with_mbuf_alloc(struct worker_params *wp, struct rte_mempool *p) { struct rte_distributor *d = wp->dist; unsigned i; struct rte_mbuf *bufs[BURST]; printf("=== Sanity test with mbuf alloc/free (%s) ===\n", wp->name); clear_packet_count(); for (i = 0; i < ((1<<ITER_POWER)); i += BURST) { unsigned j; while (rte_mempool_get_bulk(p, (void *)bufs, BURST) < 0) rte_distributor_process(d, NULL, 0); for (j = 0; j < BURST; j++) { bufs[j]->hash.usr = (i+j) << 1; rte_mbuf_refcnt_set(bufs[j], 1); } rte_distributor_process(d, bufs, BURST); } rte_distributor_flush(d); rte_delay_us(10000); if (total_packet_count() < (1<<ITER_POWER)) { printf("Line %u: Packet count is incorrect, %u, expected %u\n", __LINE__, total_packet_count(), (1<<ITER_POWER)); return -1; } printf("Sanity test with mbuf alloc/free passed\n\n"); return 0; }
/* do basic sanity testing of the distributor. This test tests the following: * - send 32 packets through distributor with the same tag and ensure they * all go to the one worker * - send 32 packets throught the distributor with two different tags and * verify that they go equally to two different workers. * - send 32 packets with different tags through the distributors and * just verify we get all packets back. * - send 1024 packets through the distributor, gathering the returned packets * as we go. Then verify that we correctly got all 1024 pointers back again, * not necessarily in the same order (as different flows). */ static int sanity_test(struct rte_distributor *d, struct rte_mempool *p) { struct rte_mbuf *bufs[BURST]; unsigned i; printf("=== Basic distributor sanity tests ===\n"); clear_packet_count(); if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { printf("line %d: Error getting mbufs from pool\n", __LINE__); return -1; } /* now set all hash values in all buffers to zero, so all pkts go to the * one worker thread */ for (i = 0; i < BURST; i++) bufs[i]->pkt.hash.rss = 0; rte_distributor_process(d, bufs, BURST); rte_distributor_flush(d); if (total_packet_count() != BURST) { printf("Line %d: Error, not all packets flushed. " "Expected %u, got %u\n", __LINE__, BURST, total_packet_count()); return -1; } for (i = 0; i < rte_lcore_count() - 1; i++) printf("Worker %u handled %u packets\n", i, worker_stats[i].handled_packets); printf("Sanity test with all zero hashes done.\n"); if (worker_stats[0].handled_packets != BURST) return -1; /* pick two flows and check they go correctly */ if (rte_lcore_count() >= 3) { clear_packet_count(); for (i = 0; i < BURST; i++) bufs[i]->pkt.hash.rss = (i & 1) << 8; rte_distributor_process(d, bufs, BURST); rte_distributor_flush(d); if (total_packet_count() != BURST) { printf("Line %d: Error, not all packets flushed. " "Expected %u, got %u\n", __LINE__, BURST, total_packet_count()); return -1; } for (i = 0; i < rte_lcore_count() - 1; i++) printf("Worker %u handled %u packets\n", i, worker_stats[i].handled_packets); printf("Sanity test with two hash values done\n"); if (worker_stats[0].handled_packets != 16 || worker_stats[1].handled_packets != 16) return -1; } /* give a different hash value to each packet, * so load gets distributed */ clear_packet_count(); for (i = 0; i < BURST; i++) bufs[i]->pkt.hash.rss = i; rte_distributor_process(d, bufs, BURST); rte_distributor_flush(d); if (total_packet_count() != BURST) { printf("Line %d: Error, not all packets flushed. " "Expected %u, got %u\n", __LINE__, BURST, total_packet_count()); return -1; } for (i = 0; i < rte_lcore_count() - 1; i++) printf("Worker %u handled %u packets\n", i, worker_stats[i].handled_packets); printf("Sanity test with non-zero hashes done\n"); rte_mempool_put_bulk(p, (void *)bufs, BURST); /* sanity test with BIG_BATCH packets to ensure they all arrived back * from the returned packets function */ clear_packet_count(); struct rte_mbuf *many_bufs[BIG_BATCH], *return_bufs[BIG_BATCH]; unsigned num_returned = 0; /* flush out any remaining packets */ rte_distributor_flush(d); rte_distributor_clear_returns(d); if (rte_mempool_get_bulk(p, (void *)many_bufs, BIG_BATCH) != 0) { printf("line %d: Error getting mbufs from pool\n", __LINE__); return -1; } for (i = 0; i < BIG_BATCH; i++) many_bufs[i]->pkt.hash.rss = i << 2; for (i = 0; i < BIG_BATCH/BURST; i++) { rte_distributor_process(d, &many_bufs[i*BURST], BURST); num_returned += rte_distributor_returned_pkts(d, &return_bufs[num_returned], BIG_BATCH - num_returned); } rte_distributor_flush(d); num_returned += rte_distributor_returned_pkts(d, &return_bufs[num_returned], BIG_BATCH - num_returned); if (num_returned != BIG_BATCH) { printf("line %d: Number returned is not the same as " "number sent\n", __LINE__); return -1; } /* big check - make sure all packets made it back!! */ for (i = 0; i < BIG_BATCH; i++) { unsigned j; struct rte_mbuf *src = many_bufs[i]; for (j = 0; j < BIG_BATCH; j++) if (return_bufs[j] == src) break; if (j == BIG_BATCH) { printf("Error: could not find source packet #%u\n", i); return -1; } } printf("Sanity test of returned packets done\n"); rte_mempool_put_bulk(p, (void *)many_bufs, BIG_BATCH); printf("\n"); return 0; }
/* do basic sanity testing of the distributor. This test tests the following: * - send 32 packets through distributor with the same tag and ensure they * all go to the one worker * - send 32 packets through the distributor with two different tags and * verify that they go equally to two different workers. * - send 32 packets with different tags through the distributors and * just verify we get all packets back. * - send 1024 packets through the distributor, gathering the returned packets * as we go. Then verify that we correctly got all 1024 pointers back again, * not necessarily in the same order (as different flows). */ static int sanity_test(struct worker_params *wp, struct rte_mempool *p) { struct rte_distributor *db = wp->dist; struct rte_mbuf *bufs[BURST]; struct rte_mbuf *returns[BURST*2]; unsigned int i, count; unsigned int retries; printf("=== Basic distributor sanity tests ===\n"); clear_packet_count(); if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { printf("line %d: Error getting mbufs from pool\n", __LINE__); return -1; } /* now set all hash values in all buffers to zero, so all pkts go to the * one worker thread */ for (i = 0; i < BURST; i++) bufs[i]->hash.usr = 0; rte_distributor_process(db, bufs, BURST); count = 0; do { rte_distributor_flush(db); count += rte_distributor_returned_pkts(db, returns, BURST*2); } while (count < BURST); if (total_packet_count() != BURST) { printf("Line %d: Error, not all packets flushed. " "Expected %u, got %u\n", __LINE__, BURST, total_packet_count()); return -1; } for (i = 0; i < rte_lcore_count() - 1; i++) printf("Worker %u handled %u packets\n", i, worker_stats[i].handled_packets); printf("Sanity test with all zero hashes done.\n"); /* pick two flows and check they go correctly */ if (rte_lcore_count() >= 3) { clear_packet_count(); for (i = 0; i < BURST; i++) bufs[i]->hash.usr = (i & 1) << 8; rte_distributor_process(db, bufs, BURST); count = 0; do { rte_distributor_flush(db); count += rte_distributor_returned_pkts(db, returns, BURST*2); } while (count < BURST); if (total_packet_count() != BURST) { printf("Line %d: Error, not all packets flushed. " "Expected %u, got %u\n", __LINE__, BURST, total_packet_count()); return -1; } for (i = 0; i < rte_lcore_count() - 1; i++) printf("Worker %u handled %u packets\n", i, worker_stats[i].handled_packets); printf("Sanity test with two hash values done\n"); } /* give a different hash value to each packet, * so load gets distributed */ clear_packet_count(); for (i = 0; i < BURST; i++) bufs[i]->hash.usr = i+1; rte_distributor_process(db, bufs, BURST); count = 0; do { rte_distributor_flush(db); count += rte_distributor_returned_pkts(db, returns, BURST*2); } while (count < BURST); if (total_packet_count() != BURST) { printf("Line %d: Error, not all packets flushed. " "Expected %u, got %u\n", __LINE__, BURST, total_packet_count()); return -1; } for (i = 0; i < rte_lcore_count() - 1; i++) printf("Worker %u handled %u packets\n", i, worker_stats[i].handled_packets); printf("Sanity test with non-zero hashes done\n"); rte_mempool_put_bulk(p, (void *)bufs, BURST); /* sanity test with BIG_BATCH packets to ensure they all arrived back * from the returned packets function */ clear_packet_count(); struct rte_mbuf *many_bufs[BIG_BATCH], *return_bufs[BIG_BATCH]; unsigned num_returned = 0; /* flush out any remaining packets */ rte_distributor_flush(db); rte_distributor_clear_returns(db); if (rte_mempool_get_bulk(p, (void *)many_bufs, BIG_BATCH) != 0) { printf("line %d: Error getting mbufs from pool\n", __LINE__); return -1; } for (i = 0; i < BIG_BATCH; i++) many_bufs[i]->hash.usr = i << 2; printf("=== testing big burst (%s) ===\n", wp->name); for (i = 0; i < BIG_BATCH/BURST; i++) { rte_distributor_process(db, &many_bufs[i*BURST], BURST); count = rte_distributor_returned_pkts(db, &return_bufs[num_returned], BIG_BATCH - num_returned); num_returned += count; } rte_distributor_flush(db); count = rte_distributor_returned_pkts(db, &return_bufs[num_returned], BIG_BATCH - num_returned); num_returned += count; retries = 0; do { rte_distributor_flush(db); count = rte_distributor_returned_pkts(db, &return_bufs[num_returned], BIG_BATCH - num_returned); num_returned += count; retries++; } while ((num_returned < BIG_BATCH) && (retries < 100)); if (num_returned != BIG_BATCH) { printf("line %d: Missing packets, expected %d\n", __LINE__, num_returned); return -1; } /* big check - make sure all packets made it back!! */ for (i = 0; i < BIG_BATCH; i++) { unsigned j; struct rte_mbuf *src = many_bufs[i]; for (j = 0; j < BIG_BATCH; j++) { if (return_bufs[j] == src) break; } if (j == BIG_BATCH) { printf("Error: could not find source packet #%u\n", i); return -1; } } printf("Sanity test of returned packets done\n"); rte_mempool_put_bulk(p, (void *)many_bufs, BIG_BATCH); printf("\n"); return 0; }