1 /**
2 * Copyright (C) Mellanox Technologies Ltd. 2001-2017.  ALL RIGHTS RESERVED.
3 *
4 * See file LICENSE for terms.
5 */
6 
7 #include "test_ucp_tag.h"
8 
9 
10 class test_ucp_tag_perf : public test_ucp_tag {
11 public:
init()12     virtual void init() {
13         if (RUNNING_ON_VALGRIND) {
14             UCS_TEST_SKIP_R("valgrind");
15         }
16         test_ucp_tag::init();
17     }
18 
19 protected:
20     static const size_t    COUNT    = 8192;
21     static const ucp_tag_t TAG_MASK = 0xffffffffffffffffUL;
22 
23     double check_perf(size_t count, bool is_exp);
24     void check_scalability(double max_growth, bool is_exp);
25     void do_sends(size_t count);
26 };
27 
check_perf(size_t count,bool is_exp)28 double test_ucp_tag_perf::check_perf(size_t count, bool is_exp)
29 {
30     ucs_time_t start_time;
31 
32     if (is_exp) {
33         std::vector<request*> rreqs;
34 
35         for (size_t i = 0; i < count; ++i) {
36             request *rreq = recv_nb(NULL, 0, DATATYPE, i, TAG_MASK);
37             assert(!UCS_PTR_IS_ERR(rreq));
38             EXPECT_FALSE(rreq->completed);
39             rreqs.push_back(rreq);
40         }
41 
42         start_time = ucs_get_time();
43         do_sends(count);
44         while (!rreqs.empty()) {
45             request *rreq = rreqs.back();
46             rreqs.pop_back();
47             wait_and_validate(rreq);
48         }
49     } else {
50         ucp_tag_recv_info_t info;
51 
52         send_b(NULL, 0, DATATYPE, 0xdeadbeef);
53         do_sends(count);
54         recv_b(NULL, 0, DATATYPE, 0xdeadbeef, TAG_MASK, &info);
55 
56         start_time = ucs_get_time();
57         for (size_t i = 0; i < count; ++i) {
58             recv_b(NULL, 0, DATATYPE, i, TAG_MASK, &info);
59         }
60     }
61 
62     return ucs_time_to_sec(ucs_get_time() - start_time) / count;
63 }
64 
do_sends(size_t count)65 void test_ucp_tag_perf::do_sends(size_t count)
66 {
67     size_t i = count;
68     while (i > 0) {
69         --i;
70         send_b(NULL, 0, DATATYPE, i);
71     }
72 }
73 
check_scalability(double max_growth,bool is_exp)74 void test_ucp_tag_perf::check_scalability(double max_growth, bool is_exp)
75 {
76     double prev_time = 0.0, total_growth = 0.0, avg_growth;
77     size_t n = 0;
78 
79     for (int i = 0; i < (ucs::perf_retry_count + 1); ++i) {
80 
81         /* Estimate by how much the tag matching time grows when the matching queue
82          * length grows by 2x. A result close to 1.0 means O(1) scalability (which
83          * is good), while a result of 2.0 or higher means O(n) or higher.
84          */
85         for (size_t count = 1; count <= COUNT; count *= 2) {
86             size_t iters = 10 * ucs_max(1ul, COUNT / count);
87             double total_time = 0;
88             for (size_t i = 0; i < iters; ++i) {
89                 total_time += check_perf(count, is_exp);
90             }
91 
92             double time = total_time / iters;
93             if (count >= 16) {
94                 /* don't measure first few iterations - warmup */
95                 total_growth += (time / prev_time);
96                 ++n;
97             }
98             prev_time = time;
99         }
100 
101         avg_growth = total_growth / n;
102         UCS_TEST_MESSAGE << "Average growth: " << avg_growth;
103 
104         if (!ucs::perf_retry_count) {
105             UCS_TEST_MESSAGE << "not validating performance";
106             return; /* Skip */
107         } else if (avg_growth < max_growth) {
108             return; /* Success */
109         } else {
110             ucs::safe_sleep(ucs::perf_retry_interval);
111         }
112     }
113 
114     ADD_FAILURE() << "Tag matching is not scalable";
115 }
116 
UCS_TEST_P(test_ucp_tag_perf,multi_exp)117 UCS_TEST_P(test_ucp_tag_perf, multi_exp) {
118     check_scalability(1.5, true);
119 }
120 
UCS_TEST_P(test_ucp_tag_perf,multi_unexp)121 UCS_TEST_P(test_ucp_tag_perf, multi_unexp) {
122     check_scalability(1.5, false);
123 }
124 
125 UCP_INSTANTIATE_TEST_CASE(test_ucp_tag_perf)
126