xref: /OK3568_Linux_fs/yocto/poky/bitbake/bin/bitbake-hashclient (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#! /usr/bin/env python3
2*4882a593Smuzhiyun#
3*4882a593Smuzhiyun# Copyright (C) 2019 Garmin Ltd.
4*4882a593Smuzhiyun#
5*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only
6*4882a593Smuzhiyun#
7*4882a593Smuzhiyun
8*4882a593Smuzhiyunimport argparse
9*4882a593Smuzhiyunimport hashlib
10*4882a593Smuzhiyunimport logging
11*4882a593Smuzhiyunimport os
12*4882a593Smuzhiyunimport pprint
13*4882a593Smuzhiyunimport sys
14*4882a593Smuzhiyunimport threading
15*4882a593Smuzhiyunimport time
16*4882a593Smuzhiyunimport warnings
17*4882a593Smuzhiyunwarnings.simplefilter("default")
18*4882a593Smuzhiyun
19*4882a593Smuzhiyuntry:
20*4882a593Smuzhiyun    import tqdm
21*4882a593Smuzhiyun    ProgressBar = tqdm.tqdm
22*4882a593Smuzhiyunexcept ImportError:
23*4882a593Smuzhiyun    class ProgressBar(object):
24*4882a593Smuzhiyun        def __init__(self, *args, **kwargs):
25*4882a593Smuzhiyun            pass
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun        def __enter__(self):
28*4882a593Smuzhiyun            return self
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun        def __exit__(self, *args, **kwargs):
31*4882a593Smuzhiyun            pass
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun        def update(self):
34*4882a593Smuzhiyun            pass
35*4882a593Smuzhiyun
36*4882a593Smuzhiyunsys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib'))
37*4882a593Smuzhiyun
38*4882a593Smuzhiyunimport hashserv
39*4882a593Smuzhiyun
40*4882a593SmuzhiyunDEFAULT_ADDRESS = 'unix://./hashserve.sock'
41*4882a593SmuzhiyunMETHOD = 'stress.test.method'
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun
44*4882a593Smuzhiyundef main():
45*4882a593Smuzhiyun    def handle_stats(args, client):
46*4882a593Smuzhiyun        if args.reset:
47*4882a593Smuzhiyun            s = client.reset_stats()
48*4882a593Smuzhiyun        else:
49*4882a593Smuzhiyun            s = client.get_stats()
50*4882a593Smuzhiyun        pprint.pprint(s)
51*4882a593Smuzhiyun        return 0
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun    def handle_stress(args, client):
54*4882a593Smuzhiyun        def thread_main(pbar, lock):
55*4882a593Smuzhiyun            nonlocal found_hashes
56*4882a593Smuzhiyun            nonlocal missed_hashes
57*4882a593Smuzhiyun            nonlocal max_time
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun            client = hashserv.create_client(args.address)
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun            for i in range(args.requests):
62*4882a593Smuzhiyun                taskhash = hashlib.sha256()
63*4882a593Smuzhiyun                taskhash.update(args.taskhash_seed.encode('utf-8'))
64*4882a593Smuzhiyun                taskhash.update(str(i).encode('utf-8'))
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun                start_time = time.perf_counter()
67*4882a593Smuzhiyun                l = client.get_unihash(METHOD, taskhash.hexdigest())
68*4882a593Smuzhiyun                elapsed = time.perf_counter() - start_time
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun                with lock:
71*4882a593Smuzhiyun                    if l:
72*4882a593Smuzhiyun                        found_hashes += 1
73*4882a593Smuzhiyun                    else:
74*4882a593Smuzhiyun                        missed_hashes += 1
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun                    max_time = max(elapsed, max_time)
77*4882a593Smuzhiyun                    pbar.update()
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun        max_time = 0
80*4882a593Smuzhiyun        found_hashes = 0
81*4882a593Smuzhiyun        missed_hashes = 0
82*4882a593Smuzhiyun        lock = threading.Lock()
83*4882a593Smuzhiyun        total_requests = args.clients * args.requests
84*4882a593Smuzhiyun        start_time = time.perf_counter()
85*4882a593Smuzhiyun        with ProgressBar(total=total_requests) as pbar:
86*4882a593Smuzhiyun            threads = [threading.Thread(target=thread_main, args=(pbar, lock), daemon=False) for _ in range(args.clients)]
87*4882a593Smuzhiyun            for t in threads:
88*4882a593Smuzhiyun                t.start()
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun            for t in threads:
91*4882a593Smuzhiyun                t.join()
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun        elapsed = time.perf_counter() - start_time
94*4882a593Smuzhiyun        with lock:
95*4882a593Smuzhiyun            print("%d requests in %.1fs. %.1f requests per second" % (total_requests, elapsed, total_requests / elapsed))
96*4882a593Smuzhiyun            print("Average request time %.8fs" % (elapsed / total_requests))
97*4882a593Smuzhiyun            print("Max request time was %.8fs" % max_time)
98*4882a593Smuzhiyun            print("Found %d hashes, missed %d" % (found_hashes, missed_hashes))
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun        if args.report:
101*4882a593Smuzhiyun            with ProgressBar(total=args.requests) as pbar:
102*4882a593Smuzhiyun                for i in range(args.requests):
103*4882a593Smuzhiyun                    taskhash = hashlib.sha256()
104*4882a593Smuzhiyun                    taskhash.update(args.taskhash_seed.encode('utf-8'))
105*4882a593Smuzhiyun                    taskhash.update(str(i).encode('utf-8'))
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun                    outhash = hashlib.sha256()
108*4882a593Smuzhiyun                    outhash.update(args.outhash_seed.encode('utf-8'))
109*4882a593Smuzhiyun                    outhash.update(str(i).encode('utf-8'))
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun                    client.report_unihash(taskhash.hexdigest(), METHOD, outhash.hexdigest(), taskhash.hexdigest())
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun                    with lock:
114*4882a593Smuzhiyun                        pbar.update()
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun    parser = argparse.ArgumentParser(description='Hash Equivalence Client')
117*4882a593Smuzhiyun    parser.add_argument('--address', default=DEFAULT_ADDRESS, help='Server address (default "%(default)s")')
118*4882a593Smuzhiyun    parser.add_argument('--log', default='WARNING', help='Set logging level')
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun    subparsers = parser.add_subparsers()
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun    stats_parser = subparsers.add_parser('stats', help='Show server stats')
123*4882a593Smuzhiyun    stats_parser.add_argument('--reset', action='store_true',
124*4882a593Smuzhiyun                              help='Reset server stats')
125*4882a593Smuzhiyun    stats_parser.set_defaults(func=handle_stats)
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun    stress_parser = subparsers.add_parser('stress', help='Run stress test')
128*4882a593Smuzhiyun    stress_parser.add_argument('--clients', type=int, default=10,
129*4882a593Smuzhiyun                               help='Number of simultaneous clients')
130*4882a593Smuzhiyun    stress_parser.add_argument('--requests', type=int, default=1000,
131*4882a593Smuzhiyun                               help='Number of requests each client will perform')
132*4882a593Smuzhiyun    stress_parser.add_argument('--report', action='store_true',
133*4882a593Smuzhiyun                               help='Report new hashes')
134*4882a593Smuzhiyun    stress_parser.add_argument('--taskhash-seed', default='',
135*4882a593Smuzhiyun                               help='Include string in taskhash')
136*4882a593Smuzhiyun    stress_parser.add_argument('--outhash-seed', default='',
137*4882a593Smuzhiyun                               help='Include string in outhash')
138*4882a593Smuzhiyun    stress_parser.set_defaults(func=handle_stress)
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun    args = parser.parse_args()
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun    logger = logging.getLogger('hashserv')
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun    level = getattr(logging, args.log.upper(), None)
145*4882a593Smuzhiyun    if not isinstance(level, int):
146*4882a593Smuzhiyun        raise ValueError('Invalid log level: %s' % args.log)
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun    logger.setLevel(level)
149*4882a593Smuzhiyun    console = logging.StreamHandler()
150*4882a593Smuzhiyun    console.setLevel(level)
151*4882a593Smuzhiyun    logger.addHandler(console)
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun    func = getattr(args, 'func', None)
154*4882a593Smuzhiyun    if func:
155*4882a593Smuzhiyun        client = hashserv.create_client(args.address)
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun        return func(args, client)
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun    return 0
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun
162*4882a593Smuzhiyunif __name__ == '__main__':
163*4882a593Smuzhiyun    try:
164*4882a593Smuzhiyun        ret = main()
165*4882a593Smuzhiyun    except Exception:
166*4882a593Smuzhiyun        ret = 1
167*4882a593Smuzhiyun        import traceback
168*4882a593Smuzhiyun        traceback.print_exc()
169*4882a593Smuzhiyun    sys.exit(ret)
170