GNUnet 0.21.1
benchmark.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "benchmark.h"
31#include <pthread.h>
32#include <sys/syscall.h>
33
37static pthread_key_t key;
38
42static pthread_once_t key_once = PTHREAD_ONCE_INIT;
43
44
50static void
52{
54 pid_t pid = getpid ();
55 pid_t tid = syscall (SYS_gettid);
56 char *benchmark_dir;
57 char *s;
58
59 benchmark_dir = getenv ("GNUNET_BENCHMARK_DIR");
60
61 if (NULL == benchmark_dir)
62 return;
63
64 if (GNUNET_OK != GNUNET_DISK_directory_create (benchmark_dir))
65 {
66 GNUNET_break (0);
67 return;
68 }
69
70 GNUNET_asprintf (&s, "%s/gnunet-benchmark-ops-%s-%llu-%llu.txt",
71 benchmark_dir,
72 (pid == tid) ? "main" : "thread",
73 (unsigned long long) pid,
74 (unsigned long long) tid);
75
82 GNUNET_assert (NULL != fh);
83 GNUNET_free (s);
84
85#define WRITE_BENCHMARK_OP(opname) do { \
86 GNUNET_asprintf (&s, "op " #opname " count %llu time_us %llu\n", \
87 (unsigned long long) bd->opname ## _count, \
88 (unsigned long long) bd->opname ## _time.rel_value_us); \
89 GNUNET_assert (GNUNET_SYSERR != GNUNET_DISK_file_write_blocking (fh, s, \
90 strlen ( \
91 s))); \
92 GNUNET_free (s); \
93} while (0)
94
95 WRITE_BENCHMARK_OP (ecc_ecdh);
96 WRITE_BENCHMARK_OP (ecdh_eddsa);
97 WRITE_BENCHMARK_OP (ecdhe_key_create);
98 WRITE_BENCHMARK_OP (ecdhe_key_get_public);
99 WRITE_BENCHMARK_OP (ecdsa_ecdh);
100 WRITE_BENCHMARK_OP (ecdsa_key_create);
101 WRITE_BENCHMARK_OP (ecdsa_key_get_public);
102 WRITE_BENCHMARK_OP (ecdsa_sign);
103 WRITE_BENCHMARK_OP (ecdsa_verify);
104 WRITE_BENCHMARK_OP (eddsa_ecdh);
105 WRITE_BENCHMARK_OP (eddsa_key_create);
106 WRITE_BENCHMARK_OP (eddsa_key_get_public);
107 WRITE_BENCHMARK_OP (eddsa_sign);
108 WRITE_BENCHMARK_OP (eddsa_verify);
109 WRITE_BENCHMARK_OP (hash);
110 WRITE_BENCHMARK_OP (hash_context_finish);
111 WRITE_BENCHMARK_OP (hash_context_read);
112 WRITE_BENCHMARK_OP (hash_context_start);
113 WRITE_BENCHMARK_OP (hkdf);
114 WRITE_BENCHMARK_OP (rsa_blind);
115 WRITE_BENCHMARK_OP (rsa_private_key_create);
116 WRITE_BENCHMARK_OP (rsa_private_key_get_public);
117 WRITE_BENCHMARK_OP (rsa_sign_blinded);
118 WRITE_BENCHMARK_OP (rsa_unblind);
119 WRITE_BENCHMARK_OP (rsa_verify);
120
121#undef WRITE_BENCHMARK_OP
122
124
125 GNUNET_asprintf (&s, "%s/gnunet-benchmark-urls-%s-%llu-%llu.txt",
126 benchmark_dir,
127 (pid == tid) ? "main" : "thread",
128 (unsigned long long) pid,
129 (unsigned long long) tid);
130
137 GNUNET_assert (NULL != fh);
138 GNUNET_free (s);
139
140 for (unsigned int i = 0; i < bd->urd_len; i++)
141 {
142 struct UrlRequestData *urd = &bd->urd[i];
143 GNUNET_asprintf (&s,
144 "url %s status %u count %llu time_us %llu time_us_max %llu bytes_sent %llu bytes_received %llu\n",
145 urd->request_url,
146 urd->status,
147 (unsigned long long) urd->count,
148 (unsigned long long) urd->time.rel_value_us,
149 (unsigned long long) urd->time_max.rel_value_us,
150 (unsigned long long) urd->bytes_sent,
151 (unsigned long long) urd->bytes_received);
153 strlen (
154 s)));
155 GNUNET_free (s);
156 }
157
159}
160
161
165static void
167{
168 struct BenchmarkData *bd;
169
170 bd = pthread_getspecific (key);
171 if (NULL != bd)
173}
174
175
181static void
183{
184 struct BenchmarkData *bd = cls;
185
186 // main thread will be handled by atexit
187 if (getpid () == (pid_t) syscall (SYS_gettid))
188 return;
189
190 GNUNET_assert (NULL != bd);
192}
193
194
198static void
200{
201 (void) pthread_key_create (&key, &thread_destructor);
202}
203
204
211struct BenchmarkData *
213{
214 struct BenchmarkData *bd;
215
216 (void) pthread_once (&key_once, &make_key);
217
218 if (NULL == (bd = pthread_getspecific (key)))
219 {
220 bd = GNUNET_new (struct BenchmarkData);
221 (void) pthread_setspecific (key, bd);
222 if (getpid () == (pid_t) syscall (SYS_gettid))
223 {
224 // We're the main thread!
225 atexit (main_thread_destructor);
226 }
227 }
228 return bd;
229}
230
231
241struct UrlRequestData *
242get_url_benchmark_data (char *url, unsigned int status)
243{
244 char trunc[MAX_BENCHMARK_URL_LEN];
245 struct BenchmarkData *bd;
246
247 if (NULL == url)
248 {
249 /* Should not happen unless curl barfs */
250 GNUNET_break (0);
251 url = "<empty>";
252 }
253
254 memcpy (trunc, url, MAX_BENCHMARK_URL_LEN);
255 trunc[MAX_BENCHMARK_URL_LEN - 1] = 0;
256
257 /* We're not interested in what's after the query string */
258 for (size_t i = 0; i < strlen (trunc); i++)
259 {
260 if (trunc[i] == '?')
261 {
262 trunc[i] = 0;
263 break;
264 }
265 }
266
267 bd = get_benchmark_data ();
268
270
271 for (unsigned int i = 0; i < bd->urd_len; i++)
272 {
273 if ((0 == strcmp (trunc, bd->urd[i].request_url)) &&
274 (bd->urd[i].status == status))
275 return &bd->urd[i];
276 }
277
278 {
279 struct UrlRequestData urd = { 0 };
280
281 memcpy (&urd.request_url, trunc, MAX_BENCHMARK_URL_LEN);
282 urd.status = status;
283
284 if (bd->urd_len == bd->urd_capacity)
285 {
286 bd->urd_capacity = 2 * (bd->urd_capacity + 1);
287 bd->urd = GNUNET_realloc (bd->urd, bd->urd_capacity * sizeof(struct
289 }
290
291 bd->urd[bd->urd_len++] = urd;
292 return &bd->urd[bd->urd_len - 1];
293 }
294}
static void make_key()
Initialize the thread-local variable key for benchmark data.
Definition: benchmark.c:199
#define WRITE_BENCHMARK_OP(opname)
struct UrlRequestData * get_url_benchmark_data(char *url, unsigned int status)
Get benchmark data for a URL.
Definition: benchmark.c:242
static void thread_destructor(void *cls)
Called when a thread exits and benchmark data for it was created.
Definition: benchmark.c:182
static pthread_once_t key_once
One-time initialization marker for key.
Definition: benchmark.c:42
static void main_thread_destructor()
Called when the main thread exits and benchmark data for it was created.
Definition: benchmark.c:166
struct BenchmarkData * get_benchmark_data(void)
Acquire the benchmark data for the current thread, allocate if necessary.
Definition: benchmark.c:212
static pthread_key_t key
Thread-local storage key for the benchmark data.
Definition: benchmark.c:37
static void write_benchmark_data(struct BenchmarkData *bd)
Write benchmark data to a file.
Definition: benchmark.c:51
benchmarking for various operations
#define MAX_BENCHMARK_URL_LEN
Maximum length of URLs considered for benchmarking.
Definition: benchmark.h:36
char * getenv()
static int status
The program status; 0 for success.
Definition: gnunet-nse.c:39
static struct GNUNET_SCHEDULER_Task * tid
Task identifier of the task that waits for stdin.
static struct GNUNET_DISK_FileHandle * fh
File handle to STDIN, for reading restart/quit commands.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
struct GNUNET_DISK_FileHandle * GNUNET_DISK_file_open(const char *fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm)
Open a file.
Definition: disk.c:1237
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1308
ssize_t GNUNET_DISK_file_write_blocking(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file, blocking, if necessary.
Definition: disk.c:701
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_create(const char *dir)
Implementation of "mkdir -p".
Definition: disk.c:496
@ GNUNET_DISK_OPEN_WRITE
Open the file for writing.
@ GNUNET_DISK_OPEN_TRUNCATE
Truncate file if it exists.
@ GNUNET_DISK_OPEN_CREATE
Create file if it doesn't exist.
@ GNUNET_DISK_PERM_USER_READ
Owner can read.
@ GNUNET_DISK_PERM_USER_WRITE
Owner can write.
@ GNUNET_OK
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
#define GNUNET_free(ptr)
Wrapper around free.
Thread-local struct for benchmarking data.
Definition: benchmark.h:116
unsigned int urd_capacity
Definition: benchmark.h:147
struct UrlRequestData * urd
Definition: benchmark.h:143
unsigned int urd_len
Definition: benchmark.h:145
Handle used to access files (and pipes).
uint64_t rel_value_us
The actual value.
Struct for benchmark data for one URL.
Definition: benchmark.h:66
struct GNUNET_TIME_Relative time
Total time spent requesting this URL.
Definition: benchmark.h:95
char request_url[128]
Request URL, truncated (but 0-terminated).
Definition: benchmark.h:70
unsigned int status
HTTP status code.
Definition: benchmark.h:75
uint64_t bytes_received
How many bytes were received in total as response to requesting this URL.
Definition: benchmark.h:90
struct GNUNET_TIME_Relative time_max
Slowest time to response.
Definition: benchmark.h:100
uint64_t bytes_sent
How many bytes were sent in total to request the URL.
Definition: benchmark.h:85
uint64_t count
How often was the URL requested?
Definition: benchmark.h:80