From fa820014f9bfda90fbc43b54ff8e44aded106e1a Mon Sep 17 00:00:00 2001 From: Unsung Lee Date: Fri, 17 Sep 2021 17:18:15 +0900 Subject: [PATCH] Add IPC benchmark Change-Id: Ia886f1d1d123185205d04f15efcc60deeb9909b6 Signed-off-by: Unsung Lee Add IPC benchmark Change-Id: Ia886f1d1d123185205d04f15efcc60deeb9909b6 Signed-off-by: Unsung Lee Signed-off-by: Hyotaek Shim Signed-off-by: Unsung Lee --- Makefile | 22 ++ benchmark/common.c | 26 +++ benchmark/common.h | 29 +++ benchmark/gdbus.c | 447 +++++++++++++++++++++++++++++++++++++ benchmark/libdbus.c | 409 ++++++++++++++++++++++++++++++++++ benchmark/pipe.c | 365 ++++++++++++++++++++++++++++++ benchmark/sharedmem.c | 456 ++++++++++++++++++++++++++++++++++++++ benchmark/socket.c | 362 ++++++++++++++++++++++++++++++ benchmark/test_pc.sh | 29 +++ benchmark/test_target.sh | 21 ++ packaging/dbus-tools.spec | 23 +- 11 files changed, 2188 insertions(+), 1 deletion(-) create mode 100644 benchmark/common.c create mode 100644 benchmark/common.h create mode 100644 benchmark/gdbus.c create mode 100644 benchmark/libdbus.c create mode 100644 benchmark/pipe.c create mode 100644 benchmark/sharedmem.c create mode 100644 benchmark/socket.c create mode 100755 benchmark/test_pc.sh create mode 100755 benchmark/test_target.sh diff --git a/Makefile b/Makefile index a004069..62def2e 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,24 @@ +CFLAGS= -D_GNU_SOURCE +CFLAGS+= -I/usr/include/dlog -I/usr/lib/glib-2.0/include -I/usr/include/glib-2.0 +CFLAGS+= -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -L/usr/lib +CFLAGS+=-Wall -O2 -g +LDFLAGS= -lglib-2.0 -lgobject-2.0 -lgio-2.0 -lgmodule-2.0 -ldbus-1 -lgthread-2.0 -lpthread -lrt -lpcre +LDFLAGS+=-lm +DFTSRC=benchmark/common.c + +all: + gcc $(CFLAGS) -pg -o benchmark/pipe $(DFTSRC) benchmark/pipe.c $(LDFLAGS) + gcc $(CFLAGS) -o benchmark/socket $(DFTSRC) benchmark/socket.c $(LDFLAGS) + gcc $(CFLAGS) -o benchmark/sharedmem $(DFTSRC) benchmark/sharedmem.c $(LDFLAGS) + gcc $(CFLAGS) -o benchmark/gdbus $(DFTSRC) benchmark/gdbus.c $(LDFLAGS) + gcc $(CFLAGS) -o benchmark/libdbus $(DFTSRC) benchmark/libdbus.c $(LDFLAGS) + + install: make -C policychecker install + mkdir -p $(DESTDIR)/usr/bin + cp benchmark/pipe $(DESTDIR)/usr/bin/pipe + cp benchmark/socket $(DESTDIR)/usr/bin/socket + cp benchmark/sharedmem $(DESTDIR)/usr/bin/sharedmem + cp benchmark/gdbus $(DESTDIR)/usr/bin/gdbus + cp benchmark/libdbus $(DESTDIR)/usr/bin/libdbus diff --git a/benchmark/common.c b/benchmark/common.c new file mode 100644 index 0000000..d8d5cee --- /dev/null +++ b/benchmark/common.c @@ -0,0 +1,26 @@ +#include "common.h" + +int cpu_pin(int cpuid, int pid) { + int ncpu = get_nprocs(); + cpu_set_t set; + + cpuid %= ncpu; + + CPU_ZERO(&set); + CPU_SET(cpuid, &set); + + if(sched_setaffinity(pid, sizeof(set), &set) == -1) + return 0; + else + return 1; +} + +void print_help(char **argv) +{ + printf("%s [-m ] [-p <#process>] [-b] [-l] [-h]\n", argv[0]); + printf("-m: message size\n"); + printf("-p: the number of process (default: the number of CPU)\n"); + printf("-b: measure bandwidth\n"); + printf("-l: measure latency\n"); + printf("-h: print help page\n"); +} diff --git a/benchmark/common.h b/benchmark/common.h new file mode 100644 index 0000000..f55c3a7 --- /dev/null +++ b/benchmark/common.h @@ -0,0 +1,29 @@ +#ifndef BENCHMARK_COMMON +#define BENCHMARK_COMMON + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WARMUP_TRY 100 +#define REAL_TRY 1000 + +#define US 1000000 +#define NS 1000000000 + +#define ONE_PAGE_SIZE 4096 + +typedef enum {false, true} bool; +void print_help(char **argv); +int cpu_pin(int cpuid, int pid); + +#endif diff --git a/benchmark/gdbus.c b/benchmark/gdbus.c new file mode 100644 index 0000000..8f05062 --- /dev/null +++ b/benchmark/gdbus.c @@ -0,0 +1,447 @@ +/* + * lat_gdbus.c - gdbus IPC latency + * + */ + +#include +#include "common.h" + +typedef struct _state { + int iters; + char *buf; + bool is_lt; + GMainLoop *main_loop; +} State; + +int nprocs; +int msize; +int lt_cnt; +double min, max, total; +unsigned long long bw; + +bool lt_on, bw_on; + +static void server_name_acquired_handler (GDBusConnection *conn, const gchar *name, gpointer user_data) +{ } + +static void server_name_lost_handler (GDBusConnection *conn, const gchar *name, gpointer user_data) +{ } + +static GVariant *handle_get_property (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GError **error, + gpointer user_data) +{ } + +static gboolean handle_set_property (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GVariant *value, + GError **error, + gpointer user_data) +{ } + +static void handle_method_call (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + static int bw_cnt = 0; + static int cnt = 0; + static unsigned long long start; + unsigned long long end; + unsigned long long temp; + struct timespec clock; + State *state = (State *)user_data; + + if (g_strcmp0 (method_name, "Perf") == 0) + { + if(state->is_lt) + g_variant_get (parameters, "(ts)", &start, &state->buf); + else + g_variant_get (parameters, "(ts)", &temp, &state->buf); + + g_object_unref (invocation); + + if(++cnt == state->iters) {cnt = 0; g_main_loop_quit (state->main_loop); } + + if(state->buf[0] != 'r') + return; + + if(state->is_lt) { + clock_gettime (CLOCK_REALTIME, &clock); + end = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + + double lt = (double)(end - start) / 1000; +#ifdef DEBUG_ON + printf("latency: %0.4f\n", lt); +#endif + + if(lt > 0) { + lt_cnt++; + total += lt; + if(lt > max) + max = lt; + + if(lt < min) + min = lt; + } + } + else { + bw_cnt++; + if(bw_cnt == 1) { + clock_gettime (CLOCK_REALTIME, &clock); + start = (unsigned long long)clock.tv_sec * NS + + (unsigned long long)clock.tv_nsec; + } + + if(bw_cnt == REAL_TRY) { + clock_gettime (CLOCK_REALTIME, &clock); + end = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + bw = ((unsigned long long)NS * bw_cnt)/(end - start); + printf("bandwidth: %llu (/s)\n", bw); + } + } + } +} + +static const GDBusInterfaceVTable _vtable = +{ + handle_method_call, + handle_get_property, + handle_set_property +}; + +void Receive(register int size, const char *name, const char *path, bool is_lt) +{ + State state; + register char *buf = (char *)malloc(size); + + GMainLoop *g_main_loop = g_main_loop_new (g_main_context_default(), FALSE); + GDBusConnection *conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + g_assert(conn != NULL); + guint id = g_bus_own_name_on_connection (conn, name, G_BUS_NAME_OWNER_FLAGS_NONE + , server_name_acquired_handler + , server_name_lost_handler + , NULL, NULL); + g_assert(id != 0); + + static gchar _interface_introspection_xml[5000]; + sprintf(_interface_introspection_xml, + "" + " " + " " + " " + " " + " " + " " + " " + "", name); + + GDBusNodeInfo *introspection_data = NULL; + introspection_data = g_dbus_node_info_new_for_xml (_interface_introspection_xml, NULL); + + state.iters = WARMUP_TRY + REAL_TRY; + state.is_lt = is_lt; + state.buf = buf; + state.main_loop = g_main_loop; + + guint rid = g_dbus_connection_register_object (conn, path + , introspection_data->interfaces[0] + , &_vtable + , (gpointer)&state, NULL, NULL); + g_assert(rid > 0); + + + + g_main_loop_run (g_main_loop); + + g_dbus_connection_unregister_object(conn, rid); + g_bus_unown_name (id); + g_dbus_connection_close(conn, NULL, NULL, NULL); + g_object_unref(conn); + free(buf); +} + +void Send(register int size, const char *name, const char *path, bool is_lt) +{ + unsigned long long start; + register char *cptr = (char *)malloc(size); + GDBusConnection *conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + g_assert(conn != NULL); + + sleep(2); + for(int i = 0; i < WARMUP_TRY + REAL_TRY; i++) { + struct timespec clock; + + memset(cptr, 0, size); + if(i >= WARMUP_TRY) + cptr[0] = 'r'; + else + cptr[0] = 'w'; + + if(is_lt) { + clock_gettime (CLOCK_REALTIME, &clock); + start = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + } + else + start = 0; + + //GError *error = NULL; + g_dbus_connection_call(conn, + name, + path, + name, + "Perf", + g_variant_new ("(ts)", start, cptr), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + NULL, + NULL); + /*if(error != NULL) { + g_printerr("Error=%s\n", error->message); + g_error_free (error); + }*/ + if(is_lt) { + if(size <= ONE_PAGE_SIZE) + usleep(5000); + else if(size <= 10 * ONE_PAGE_SIZE) + usleep(10000); + else if(size <= 100 * ONE_PAGE_SIZE) + usleep(20000); + else + usleep(40000); + } + } + + g_dbus_connection_close(conn, NULL, NULL, NULL); + g_object_unref(conn); + free(cptr); +} + +void Measure_bandwidth(void) +{ + int ret; + int returnp[nprocs/2][2]; + int pids[nprocs]; + int ready_fd; + char *ready_ptr; + + ready_fd = shm_open("isready", O_CREAT | O_TRUNC | O_RDWR, 0666); + if(ready_fd == -1) + { + perror("Open"); + return; + } + if(ftruncate(ready_fd, sizeof(char))) { + perror("Ftruncate"); + return; + } + ready_ptr = mmap(0, sizeof(char), PROT_READ | PROT_WRITE, + MAP_SHARED, ready_fd, 0); + if(ready_ptr == MAP_FAILED) { + perror("Mmap"); + return; + } + close(ready_fd); + ready_ptr[0] = 'n'; + + for(int i = 0; i < nprocs/2; i++) { + if(pipe(returnp[i]) == -1) { + perror("pipe"); + exit(1); + } + } + + if(!cpu_pin(0, getpid())) { + perror("CPU pinning for parent"); + exit(1); + } + + for(int child = 1; child < nprocs; child++) { + char name[30]; + char path[30]; + + sprintf(name, "org.gdbus.server%d", child/2); + sprintf(path, "/org/gdbus/server%d", child/2); + int pid = fork(); + switch (pid) { + //child + case 0: + if(!cpu_pin(child, getpid())) { + perror("CPU pinning for child"); + exit(1); + } + + // Wait for parent + while(ready_ptr[0] == 'n') { + } + + if(child % 2 == 0) { + Receive(msize, (const char *)name, (const char *)path, false); + + //send result(bandwidth) to parent + { + int wres; + close(returnp[child/2][0]); + wres = write(returnp[child/2][1], (void *)&bw, sizeof(unsigned long long)); + if (wres != sizeof(unsigned long long)) { + perror("(write return) read/write on pipe sender"); + exit(1); + } + close(returnp[child/2][1]); + } + } + else { + Send(msize, (const char *)name, (const char *)path, false); + } + + exit(0); + case -1: + perror("fork"); + return; + default: + pids[child] = pid; + break; + } + } + + sleep(1); + ready_ptr[0] = 'y'; + + Receive(msize, "org.gdbus.server0", "/org/gdbus/server0", false); + for(int child = 1; child < nprocs; child++) { + //receive result(bandwidth) from child(s) + if(child % 2 == 0) { + int rres; + unsigned long long child_bw; + + close(returnp[child/2][1]); + rres = read(returnp[child/2][0], (void *)&child_bw, sizeof(unsigned long long)); + if (rres != sizeof(unsigned long long)) { + perror("(write return) read/write on pipe receiver"); + exit(1); + } + close(returnp[child/2][0]); + bw += child_bw; + } + + waitpid(pids[child], NULL, 0); + } + ret = munmap(ready_ptr, sizeof(bool)); + if (ret != 0) { + perror("munmap"); + exit(1); + } + + ret = shm_unlink("isready"); + if (ret != 0) { + perror("shm unlink"); + //exit(1); + } + printf("Total bandwidth: %llu (/s)\n", bw); +} + + +void Measure_latency(void) +{ + if(!cpu_pin(0, getpid())) { + perror("CPU pinning for parent"); + exit(1); + } + + int pid = fork(); + switch (pid) { + //child + case 0: + if(!cpu_pin(1, getpid())) { + perror("CPU pinning for child"); + exit(1); + } + + Send(msize, "org.gdbus.server", "/org/gdbus/server", true); + + exit(0); + case -1: + perror("fork"); + return; + default: + Receive(msize, "org.gdbus.server", "/org/gdbus/server", true); + printf("min: %0.4f(us), max: %0.4f(us), avg: %0.4f(us)\n", min, max, total/lt_cnt); + + waitpid(pid, NULL, 0); + return; + } +} + + int +main(int argc, char **argv) +{ + int opt; + extern char *optarg; + extern int optind; + + nprocs = get_nprocs(); + if(nprocs == 1) + nprocs = 2; + + msize = 3; + lt_on = bw_on = false; + while((opt = getopt(argc, argv, "m:p:blh")) != -1) { + switch(opt) { + case 'm': + msize = atoi(optarg); + break; + case 'p': + nprocs = atoi(optarg); + if(nprocs <= 0) { + printf("The number of process should be larger than 0\n"); + exit(0); + } + if(nprocs % 2 != 0) { + printf("The number of process should be even\n"); + exit(0); + } + break; + case 'b': + bw_on = true; + break; + case 'l': + lt_on = true; + break; + case 'h': + print_help(argv); + exit(0); + } + } + + if(!lt_on && !bw_on) { + print_help(argv); + exit(0); + } + + bw = 0; + lt_cnt = 0; + max = total = 0.0; + min = 1000000.0; + + if(lt_on) + Measure_latency(); + + if(bw_on) + Measure_bandwidth(); +} diff --git a/benchmark/libdbus.c b/benchmark/libdbus.c new file mode 100644 index 0000000..2beea9d --- /dev/null +++ b/benchmark/libdbus.c @@ -0,0 +1,409 @@ +/* + * lat_libdbus.c - libdbus IPC latency + * + */ + +#include +#include "common.h" + +typedef struct _state { + int iters; + char *buf; + bool is_lt; +} State; + +int nprocs; +int msize; +int lt_cnt; +double min, max, total; +unsigned long long bw; + +bool lt_on, bw_on; +bool stop; + +static void unregistered_func (DBusConnection *connection, void *user_data) +{ } + +static DBusHandlerResult message_func (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + static int bw_cnt = 0; + static int cnt = 0; + static unsigned long long start; + unsigned long long end; + unsigned long long temp; + struct timespec clock; + State *state = (State *)user_data; + + //if (dbus_message_is_method_call (message, "org.libdbus.server", "Perf")) + { + if(state->is_lt) + dbus_message_get_args (message, NULL, DBUS_TYPE_UINT64, &start, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &state->buf, &msize, DBUS_TYPE_INVALID); + else + dbus_message_get_args (message, NULL, DBUS_TYPE_UINT64, &temp, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &state->buf, &msize, DBUS_TYPE_INVALID); + + if(++cnt == state->iters) {cnt = 0; stop = true; } + + if(state->buf[0] != 'r') + return DBUS_HANDLER_RESULT_HANDLED; + + if(state->is_lt) { + clock_gettime (CLOCK_REALTIME, &clock); + end = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + + double lt = (double)(end - start) / 1000; + + if(lt) { + lt_cnt++; + total += lt; + if(lt > max) + max = lt; + + if(lt < min) + min = lt; + } + } + else { + bw_cnt++; + if(bw_cnt == 1) { + clock_gettime (CLOCK_REALTIME, &clock); + start = (unsigned long long)clock.tv_sec * NS + + (unsigned long long)clock.tv_nsec; + } + + if(bw_cnt == REAL_TRY) { + clock_gettime (CLOCK_REALTIME, &clock); + end = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + bw = ((unsigned long long)NS * bw_cnt)/(end - start); + printf("bandwidth: %llu (/s)\n", bw); + } + } + } + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusObjectPathVTable vtable = { + unregistered_func, + message_func, + NULL, +}; + + +void Receive(register int size, const char *name, const char *path, bool is_lt) +{ + State state; + DBusError error; + DBusConnection* conn; + char *buf = (char *)malloc(size); + + dbus_error_init(&error); + conn = dbus_bus_get_private(DBUS_BUS_SESSION, &error); + if (dbus_error_is_set (&error)) { + dbus_error_free (&error); + exit(1); + } + + int ret = dbus_bus_request_name (conn, name, + DBUS_NAME_FLAG_REPLACE_EXISTING|DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL); + if( ret == -1 ) { + perror("dbus_bus_request_name()\n"); + exit(1); + } + + state.iters = WARMUP_TRY + REAL_TRY; + state.is_lt = is_lt; + state.buf = buf; + dbus_connection_register_object_path (conn, path, &vtable, &state); + + //for(int i = 0; i < WARMUP_TRY + REAL_TRY; i++) { + while(1) { + if(!dbus_connection_read_write_dispatch(conn, -1)) { + printf("read on parent error\n"); + exit(1); + } + + if(stop) + break; + } + stop = false; + //} + + dbus_connection_unregister_object_path (conn, path); + free(buf); +} + +void Send(register int size, const char *name, const char *path, const char *client, bool is_lt) +{ + DBusMessage *msg; + unsigned long long start; + + char *cptr = (char *)malloc(size); + DBusConnection* conn = dbus_bus_get (DBUS_BUS_SESSION, NULL); + int ret = dbus_bus_request_name (conn, client, DBUS_NAME_FLAG_REPLACE_EXISTING, NULL); + if( ret == -1 ) { + perror("dbus_bus_request_name()\n"); + exit(1); + } + + sleep(2); + for(int i = 0; i < WARMUP_TRY + REAL_TRY; i++) { + struct timespec clock; + + memset(cptr, 0, size); + if(i >= WARMUP_TRY) + cptr[0] = 'r'; + else + cptr[0] = 'w'; + + if(is_lt) { + clock_gettime (CLOCK_REALTIME, &clock); + start = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + } + else + start = 0; + + msg = dbus_message_new_method_call (name, path, name, "Perf"); + DBusMessageIter iter; + dbus_message_iter_init_append (msg, &iter); + dbus_message_append_args (msg, + DBUS_TYPE_UINT64, &start, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cptr, size, + DBUS_TYPE_INVALID); + dbus_message_set_no_reply(msg, 1); + dbus_connection_send (conn, msg, NULL); + + if(is_lt) { + if(size <= ONE_PAGE_SIZE) + usleep(5000); + else if(size <= 10 * ONE_PAGE_SIZE) + usleep(10000); + else if(size <= 100 * ONE_PAGE_SIZE) + usleep(20000); + else + usleep(40000); + } + } + + dbus_connection_flush(conn); + dbus_message_unref (msg); + free(cptr); +} + +void Measure_bandwidth(void) +{ + int ret; + int returnp[nprocs/2][2]; + int pids[nprocs]; + int ready_fd; + char *ready_ptr; + + ready_fd = shm_open("isready", O_CREAT | O_TRUNC | O_RDWR, 0666); + if(ready_fd == -1) + { + perror("Open"); + return; + } + if(ftruncate(ready_fd, sizeof(char))) { + perror("Ftruncate"); + return; + } + ready_ptr = mmap(0, sizeof(char), PROT_READ | PROT_WRITE, + MAP_SHARED, ready_fd, 0); + if(ready_ptr == MAP_FAILED) { + perror("Mmap"); + return; + } + close(ready_fd); + ready_ptr[0] = 'n'; + + for(int i = 0; i < nprocs/2; i++) { + if(pipe(returnp[i]) == -1) { + perror("pipe"); + exit(1); + } + } + + if(!cpu_pin(0, getpid())) { + perror("CPU pinning for parent"); + exit(1); + } + + for(int child = 1; child < nprocs; child++) { + char name[30]; + char path[30]; + + sprintf(name, "org.libdbus.server%d", child/2); + sprintf(path, "/org/libdbus/server%d", child/2); + int pid = fork(); + switch (pid) { + //child + case 0: + if(!cpu_pin(child, getpid())) { + perror("CPU pinning for child"); + exit(1); + } + + // Wait for parent + while(ready_ptr[0] == 'n') { + } + + if(child % 2 == 0) { + Receive(msize, (const char *)name, (const char *)path, false); + + //send result(bandwidth) to parent + { + int wres; + close(returnp[child/2][0]); + wres = write(returnp[child/2][1], (void *)&bw, sizeof(unsigned long long)); + if (wres != sizeof(unsigned long long)) { + perror("(write return) read/write on pipe sender"); + exit(1); + } + close(returnp[child/2][1]); + } + } + else { + char client[30]; + sprintf(client, "org.libdbus.client%d", child); + Send(msize, (const char *)name, (const char *)path, (const char *)client, false); + } + + exit(0); + case -1: + perror("fork"); + return; + default: + pids[child] = pid; + break; + } + } + + sleep(1); + ready_ptr[0] = 'y'; + + Receive(msize, "org.libdbus.server0", "/org/libdbus/server0", false); + for(int child = 1; child < nprocs; child++) { + //receive result(bandwidth) from child(s) + if(child % 2 == 0) { + int rres; + unsigned long long child_bw; + + close(returnp[child/2][1]); + rres = read(returnp[child/2][0], (void *)&child_bw, sizeof(unsigned long long)); + if (rres != sizeof(unsigned long long)) { + perror("(write return) read/write on pipe receiver"); + exit(1); + } + close(returnp[child/2][0]); + bw += child_bw; + } + + waitpid(pids[child], NULL, 0); + } + ret = munmap(ready_ptr, sizeof(bool)); + if (ret != 0) { + perror("munmap"); + exit(1); + } + + ret = shm_unlink("isready"); + if (ret != 0) { + perror("shm unlink"); + //exit(1); + } + printf("Total bandwidth: %llu (/s)\n", bw); +} + +void Measure_latency(void) +{ + if(!cpu_pin(0, getpid())) { + perror("CPU pinning for parent"); + exit(1); + } + + int pid = fork(); + switch (pid) { + //child + case 0: + if(!cpu_pin(1, getpid())) { + perror("CPU pinning for child"); + exit(1); + } + + Send(msize, "org.libdbus.server", "/org/libdbus/server", "org.libdbus.client", true); + + exit(0); + case -1: + perror("fork"); + return; + default: + Receive(msize, "org.libdbus.server", "/org/libdbus/server", true); + printf("min: %0.4f(us), max: %0.4f(us), avg: %0.4f(us)\n", min, max, total/lt_cnt); + waitpid(pid, NULL, 0); + return; + } +} + + int +main(int argc, char **argv) +{ + int opt; + extern char *optarg; + extern int optind; + + nprocs = get_nprocs(); + if(nprocs == 1) + nprocs = 2; + + msize = 3; + lt_on = bw_on = false; + while((opt = getopt(argc, argv, "m:p:blh")) != -1) { + switch(opt) { + case 'm': + msize = atoi(optarg); + break; + case 'p': + nprocs = atoi(optarg); + if(nprocs <= 0) { + printf("The number of process should be larger than 0\n"); + exit(0); + } + if(nprocs % 2 != 0) { + printf("The number of process should be even\n"); + exit(0); + } + break; + case 'b': + bw_on = true; + break; + case 'l': + lt_on = true; + break; + case 'h': + print_help(argv); + exit(0); + } + } + + if(!lt_on && !bw_on) { + print_help(argv); + exit(0); + } + + bw = 0; + lt_cnt = 0; + max = total = 0.0; + min = 1000000.0; + + if(lt_on) + Measure_latency(); + + if(bw_on) + Measure_bandwidth(); +} diff --git a/benchmark/pipe.c b/benchmark/pipe.c new file mode 100644 index 0000000..9993a28 --- /dev/null +++ b/benchmark/pipe.c @@ -0,0 +1,365 @@ +/* + * lat_pipe.c - pipe IPC latency + * + */ + +#include "common.h" + +int nprocs; +int msize; +int lt_cnt; +double min, max, total; +unsigned long long bw; + +bool lt_on, bw_on; + +void Receive(int rfd1, int rfd2, register int size, bool is_lt) +{ + static int bw_cnt = 0; + unsigned long long start; + unsigned long long end; + register char *buf = (char *)malloc(size); + + for(int i = 0; i < WARMUP_TRY + REAL_TRY; i++) { + if(is_lt) { + if (read(rfd1, (void *)&start, sizeof(unsigned long long)) + != sizeof(unsigned long long)) { + perror("(read 1) read/write on pipe receiver"); + exit(1); + } + } + + if (read(rfd2, buf, size) != size) { + perror("(read 2) read/write on pipe receiver"); + exit(1); + } + else if(buf[0] == 'r') { + struct timespec clock; + if(is_lt) { + clock_gettime (CLOCK_REALTIME, &clock); + end = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + + double lt = (double)(end - start) / 1000; +#ifdef DEBUG_ON + printf("latency: %0.4f\n", lt); +#endif + + if(lt > 0) { + lt_cnt++; + total += lt; + if(lt > max) + max = lt; + + if(lt < min) + min = lt; + } + } + else { + bw_cnt++; + if(bw_cnt == 1) { + clock_gettime (CLOCK_REALTIME, &clock); + start = (unsigned long long)clock.tv_sec * NS + + (unsigned long long)clock.tv_nsec; + } + + if(bw_cnt == REAL_TRY) { + clock_gettime (CLOCK_REALTIME, &clock); + end = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + bw = ((unsigned long long)NS * bw_cnt)/(end - start); + printf("bandwidth: %llu (/s)\n", bw); + } + } + } + } + + free(buf); +} + +void Send(int wfd1, int wfd2, register int size, bool is_lt) +{ + register char *cptr = (char *)malloc(size); + + sleep(2); + for(int i = 0; i < WARMUP_TRY + REAL_TRY; i++) { + int wres1, wres2; + struct timespec clock; + + memset(cptr, 0, size); + if(i >= WARMUP_TRY) + cptr[0] = 'r'; + else + cptr[0] = 'w'; + + if(is_lt) { + clock_gettime (CLOCK_REALTIME, &clock); + unsigned long long start = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + + wres1 = write(wfd1, (void *)&start, sizeof(unsigned long long)); + if (wres1 != sizeof(unsigned long long)) { + perror("(write 1) read/write on pipe sender"); + exit(1); + } + } + wres2 = write(wfd2, cptr, size); + if (wres2 != size) { + perror("(write 2) read/write on pipe sender"); + exit(1); + } + + if(is_lt) { + if(size <= ONE_PAGE_SIZE) + usleep(5000); + else if(size <= 10 * ONE_PAGE_SIZE) + usleep(10000); + else if(size <= 100 * ONE_PAGE_SIZE) + usleep(20000); + else + usleep(40000); + } + } + + free(cptr); +} + +void Measure_bandwidth(void) +{ + int ret; + int returnp[nprocs/2][2]; + int p[nprocs/2][2]; + int pids[nprocs]; + int ready_fd; + char *ready_ptr; + + ready_fd = shm_open("isready", O_CREAT | O_TRUNC | O_RDWR, 0666); + if(ready_fd == -1) + { + perror("Open"); + return; + } + if(ftruncate(ready_fd, sizeof(char))) { + perror("Ftruncate"); + return; + } + ready_ptr = mmap(0, sizeof(char), PROT_READ | PROT_WRITE, + MAP_SHARED, ready_fd, 0); + if(ready_ptr == MAP_FAILED) { + perror("Mmap"); + return; + } + close(ready_fd); + ready_ptr[0] = "n"; + + for(int i = 0; i < nprocs/2; i++) { + if(pipe(returnp[i]) == -1) { + perror("pipe"); + exit(1); + } + } + + for(int i = 0; i < nprocs/2; i++) { + if(pipe(p[i]) == -1) { + perror("pipe"); + exit(1); + } + } + + if(!cpu_pin(0, getpid())) { + perror("CPU pinning for parent"); + exit(1); + } + + for(int child = 1; child < nprocs; child++) { + int pid = fork(); + switch (pid) { + //child + case 0: + if(!cpu_pin(child, getpid())) { + perror("CPU pinning for child"); + exit(1); + } + if(child % 2 == 0) { + close(p[child/2][1]); + } + else + close(p[child/2][0]); + + // Wait for parent + while(ready_ptr[0] == "n") { + } + + if(child % 2 == 0) { + Receive(0, p[child/2][0], msize, false); + close(p[child/2][0]); + + //send result(bandwidth) to parent + { + int wres; + close(returnp[child/2][0]); + wres = write(returnp[child/2][1], (void *)&bw, sizeof(unsigned long long)); + if (wres != sizeof(unsigned long long)) { + perror("(write return) read/write on pipe sender"); + exit(1); + } + close(returnp[child/2][1]); + } + } + else { + Send(0, p[child/2][1], msize, false); + close(p[child/2][1]); + } + + exit(0); + case -1: + perror("fork"); + return; + default: + pids[child] = pid; + } + } + + usleep(100000); + close(p[0][1]); + ready_ptr[0] = "y"; + + Receive(0, p[0][0], msize, false); + close(p[0][0]); + for(int child = 1; child < nprocs; child++) { + //receive result(bandwidth) from child(s) + if(child % 2 == 0) { + int rres; + unsigned long long child_bw; + + close(returnp[child/2][1]); + rres = read(returnp[child/2][0], (void *)&child_bw, sizeof(unsigned long long)); + if (rres != sizeof(unsigned long long)) { + perror("(read return) read/write on pipe receiver"); + exit(1); + } + close(returnp[child/2][0]); + bw += child_bw; + } + + waitpid(pids[child], NULL, 0); + } + + ret = munmap(ready_ptr, sizeof(bool)); + if (ret != 0) { + perror("munmap"); + exit(1); + } + + ret = shm_unlink("isready"); + if (ret != 0) { + perror("shm unlink"); + //exit(1); + } + printf("Total bandwidth: %llu (/s)\n", bw); +} + +void Measure_latency(void) +{ + int p1[2], p2[2]; + + if (pipe(p1) == -1) { + perror("pipe"); + exit(1); + } + if (pipe(p2) == -1) { + perror("pipe"); + exit(1); + } + + if(!cpu_pin(0, getpid())) { + perror("CPU pinning for parent"); + exit(1); + } + + int pid = fork(); + switch (pid) { + //child + case 0: + if(!cpu_pin(1, getpid())) { + perror("CPU pinning for child"); + exit(1); + } + close(p1[0]); + close(p2[0]); + Send(p1[1], p2[1], msize, true); + close(p1[1]); + close(p2[1]); + exit(0); + case -1: + perror("fork"); + return; + default: + close(p1[1]); + close(p2[1]); + Receive(p1[0], p2[0], msize, true); + close(p1[0]); + close(p2[0]); + printf("min: %0.4f(us), max: %0.4f(us), avg: %0.4f(us)\n", min, max, total/lt_cnt); + waitpid(pid, NULL, 0); + return; + } +} + + int +main(int argc, char **argv) +{ + int opt; + extern char *optarg; + extern int optind; + + nprocs = get_nprocs(); + if(nprocs == 1) + nprocs = 2; + + msize = 3; + lt_on = bw_on = false; + while((opt = getopt(argc, argv, "m:p:blh")) != -1) { + switch(opt) { + case 'm': + msize = atoi(optarg); + break; + case 'p': + nprocs = atoi(optarg); + if(nprocs <= 0) { + printf("The number of process should be larger than 0\n"); + exit(0); + } + if(nprocs % 2 != 0) { + printf("The number of process should be even\n"); + exit(0); + } + break; + case 'b': + bw_on = true; + break; + case 'l': + lt_on = true; + break; + case 'h': + print_help(argv); + exit(0); + } + } + + if(!lt_on && !bw_on) { + print_help(argv); + exit(0); + } + + bw = 0; + lt_cnt = 0; + max = total = 0.0; + min = 1000000.0; + + if(lt_on) + Measure_latency(); + + if(bw_on) + Measure_bandwidth(); +} diff --git a/benchmark/sharedmem.c b/benchmark/sharedmem.c new file mode 100644 index 0000000..a1056e6 --- /dev/null +++ b/benchmark/sharedmem.c @@ -0,0 +1,456 @@ +/* + * lat_sharedmem.c - sharedmem IPC latency + * + */ + +#include "common.h" + +#define SHM1 0 +#define SHM2 1 + +const char *shm_name1 = "sharedmem1"; +const char *shm_name2 = "sharedmem2"; + +int nprocs; +int msize; +int lt_cnt; +double min, max, total; +unsigned long long bw; + +bool lt_on, bw_on; + +void Receive(void *r1, register char *r2, register int size, bool is_lt) +{ + static int bw_cnt = 0; + unsigned long long start; + unsigned long long end; + struct timespec clock; + register char read_cnt = 0; + register char *buf = (char *)malloc(size); + + for(int i = 0; i < WARMUP_TRY + REAL_TRY; i++) { +repeat: + if(r2[1] == read_cnt) + goto repeat; + else + read_cnt = r2[1]; + + memcpy(buf, r2, size); + r2[2] = read_cnt; + if(buf[0] != 'r') + continue; + + if(is_lt) { + memcpy((void *)&start, r1, sizeof(unsigned long long)); + clock_gettime (CLOCK_REALTIME, &clock); + end = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + + double lt = (double)(end - start) / 1000; +#ifdef DEBUG_ON + printf("latency: %0.4f\n", lt); +#endif + + if(lt > 0) { + lt_cnt++; + total += lt; + if(lt > max) + max = lt; + + if(lt < min) + min = lt; + } + } + else { + bw_cnt++; + if(bw_cnt == 1) { + clock_gettime (CLOCK_REALTIME, &clock); + start = (unsigned long long)clock.tv_sec * NS + + (unsigned long long)clock.tv_nsec; + } + + if(bw_cnt == REAL_TRY) { + clock_gettime (CLOCK_REALTIME, &clock); + end = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + bw = ((unsigned long long)NS * bw_cnt)/(end - start); + printf("bandwidth: %llu (/s)\n", bw); + } + } + } + + sleep(2); + free(buf); +} + +void Send(void *w1, register char *w2, register int size, bool is_lt) +{ + register char write_cnt = 0; + register char *cptr = (char *)malloc(size); + + sleep(2); + for(int i = 0; i < WARMUP_TRY + REAL_TRY; i++) { + struct timespec clock; +repeat: + if(w2[2] == write_cnt) { + if(write_cnt == 127) + write_cnt = 1; + else + write_cnt++; + } + else { + goto repeat; + } + + memset(cptr, 0, size); + if(i >= WARMUP_TRY) + cptr[0] = 'r'; + else + cptr[0] = 'w'; + cptr[1] = write_cnt; + + if(is_lt) { + clock_gettime (CLOCK_REALTIME, &clock); + unsigned long long start = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + + memcpy(w1, (void *)&start, sizeof(unsigned long long)); + } + memcpy(w2, cptr, size); + + if(is_lt) { + if(size <= ONE_PAGE_SIZE) + usleep(5000); + else if(size <= 10 * ONE_PAGE_SIZE) + usleep(10000); + else if(size <= 100 * ONE_PAGE_SIZE) + usleep(20000); + else + usleep(40000); + } + } + + sleep(1); + memset(w2, 0, size); + free(cptr); +} + +void Measure_bandwidth(void) +{ + int ret; + char name[25]; + int returnp[nprocs/2][2]; + int shm_fd[nprocs/2]; + void *shm_ptr[nprocs/2]; + int pids[nprocs]; + int ready_fd; + char *ready_ptr; + + ready_fd = shm_open("isready", O_CREAT | O_TRUNC | O_RDWR, 0666); + if(ready_fd == -1) + { + perror("Open"); + return; + } + if(ftruncate(ready_fd, sizeof(char))) { + perror("Ftruncate"); + return; + } + ready_ptr = mmap(0, sizeof(char), PROT_READ | PROT_WRITE, + MAP_SHARED, ready_fd, 0); + if(ready_ptr == MAP_FAILED) { + perror("Mmap"); + return; + } + close(ready_fd); + ready_ptr[0] = "n"; + + for(int i = 0; i < nprocs/2; i++) { + sprintf(name, "bwsharedmem%d", i); + shm_fd[i] = shm_open(name, O_CREAT | O_TRUNC | O_RDWR, 0666); + if(shm_fd[i] == -1) + { + perror("Open"); + return; + } + if(ftruncate(shm_fd[i], msize)) { + perror("Ftruncate"); + return; + } + shm_ptr[i] = mmap(0, msize, PROT_READ | PROT_WRITE, + MAP_SHARED, shm_fd[i], 0); + if(shm_ptr[i] == MAP_FAILED) { + perror("Mmap"); + return; + } + } + + for(int i = 0; i < nprocs/2; i++) { + if(pipe(returnp[i]) == -1) { + perror("pipe"); + exit(1); + } + } + + if(!cpu_pin(0, getpid())) { + perror("CPU pinning for parent"); + exit(1); + } + + for(int child = 1; child < nprocs; child++) { + int pid = fork(); + switch (pid) { + //child + case 0: + if(!cpu_pin(child, getpid())) { + perror("CPU pinning for child"); + exit(1); + } + + // Wait for parent + while(ready_ptr[0] == "n") { + } + + if(child % 2 == 0) { + Receive(NULL, shm_ptr[child/2], msize, false); + + //send result(bandwidth) to parent + { + int wres; + close(returnp[child/2][0]); + wres = write(returnp[child/2][1], (void *)&bw, sizeof(unsigned long long)); + if (wres != sizeof(unsigned long long)) { + perror("(write return) read/write on pipe sender"); + exit(1); + } + close(returnp[child/2][1]); + } + } + else { + Send(NULL, shm_ptr[child/2], msize, false); + } + exit(0); + case -1: + perror("fork"); + return; + default: + pids[child] = pid; + break; + } + } + + sleep(1); + ready_ptr[0] = "y"; + + Receive(NULL, shm_ptr[0], msize, false); + for(int child = 1; child < nprocs; child++) { + //receive result(bandwidth) from child(s) + if(child % 2 == 0) { + int rres; + unsigned long long child_bw; + + close(returnp[child/2][1]); + rres = read(returnp[child/2][0], (void *)&child_bw, sizeof(unsigned long long)); + if (rres != sizeof(unsigned long long)) { + perror("(read return) read/write on pipe receiver"); + exit(1); + } + close(returnp[child/2][0]); + bw += child_bw; + } + + waitpid(pids[child], NULL, 0); + } + + ret = munmap(ready_ptr, sizeof(bool)); + if (ret != 0) { + perror("munmap"); + exit(1); + } + + ret = shm_unlink("isready"); + if (ret != 0) { + perror("shm unlink"); + //exit(1); + } + + for(int i = 0; i < nprocs/2; i++) { + sprintf(name, "bwsharedmem%d", i); + ret = munmap(shm_ptr[i], msize); + if (ret != 0) { + perror("munmap"); + exit(1); + } + + ret = shm_unlink(name); + if (ret != 0) { + perror("shm unlink"); + //exit(1); + } + } + + printf("Total bandwidth: %llu (/s)\n", bw); +} + +void Measure_latency(void) +{ + int ret; + int shm_fd[2]; + void *shm_ptr[2]; + // int seals = 0; + // seals | F_SEAL_SHRINK; + // seals | F_SEAL_WRITE; + //shm_fd[SHM1] = syscall(SYS_memfd_create, shm_name1, MFD_ALLOW_SEALING); + //shm_fd[SHM1] = memfd_create(shm_name1, MFD_ALLOW_SEALING); + shm_fd[SHM1] = shm_open(shm_name1, O_CREAT | O_TRUNC | O_RDWR, 0666); + if(shm_fd[SHM1] == -1) + { + perror("Open"); + return; + } + if(ftruncate(shm_fd[SHM1], sizeof(unsigned long long))) { + perror("Ftruncate"); + return; + } + shm_ptr[SHM1] = mmap(0, sizeof(unsigned long long), PROT_READ | PROT_WRITE, + MAP_SHARED, shm_fd[SHM1], 0); + if(shm_ptr[SHM1] == MAP_FAILED) { + perror("Mmap"); + return; + } + /*if(fcntl(shm_fd[SHM1], F_ADD_SEALS, seals) == -1) { + perror("Fcntl"); + return; + }*/ + + //shm_fd[SHM2] = syscall(SYS_memfd_create, shm_name2, MFD_ALLOW_SEALING); + //shm_fd[SHM2] = memfd_create(shm_name2, MFD_ALLOW_SEALING); + shm_fd[SHM2] = shm_open(shm_name2, O_CREAT | O_TRUNC | O_RDWR, 0666); + if(shm_fd[SHM2] == -1) + { + perror("Open"); + return; + } + if(ftruncate(shm_fd[SHM2], msize)) { + perror("Ftruncate"); + return; + } + shm_ptr[SHM2] = mmap(0, msize, PROT_READ | PROT_WRITE, + MAP_SHARED, shm_fd[SHM2], 0); + if(shm_ptr[SHM2] == MAP_FAILED) { + perror("Mmap"); + return; + } + /*if(fcntl(shm_fd[SHM2], F_ADD_SEALS, seals) == -1) { + perror("Fcntl"); + return; + }*/ + + if(!cpu_pin(0, getpid())) { + perror("CPU pinning for parent"); + exit(1); + } + + int pid = fork(); + switch (pid) { + //child + case 0: + if(!cpu_pin(1, getpid())) { + perror("CPU pinning for child"); + exit(1); + } + + Send(shm_ptr[SHM1], shm_ptr[SHM2], msize, true); + + exit(0); + case -1: + perror("fork"); + return; + default: + Receive(shm_ptr[SHM1], shm_ptr[SHM2], msize, true); + printf("min: %0.4f(us), max: %0.4f(us), avg: %0.4f(us)\n", min, max, total/lt_cnt); + waitpid(pid, NULL, 0); + ret = munmap(shm_ptr[SHM1], sizeof(unsigned long long)); + if (ret != 0) { + perror("munmap"); + exit(1); + } + ret = shm_unlink(shm_name1); + if (ret != 0) { + perror("munmap"); + //exit(1); + } + + ret = munmap(shm_ptr[SHM2], msize); + if (ret != 0) { + perror("munmap"); + exit(1); + } + + ret = shm_unlink(shm_name2); + if (ret != 0) { + perror("munmap"); + //exit(1); + } + + return; + } +} + + int +main(int argc, char **argv) +{ + int opt; + extern char *optarg; + extern int optind; + + nprocs = get_nprocs(); + if(nprocs == 1) + nprocs = 2; + + msize = 3; + lt_on = bw_on = false; + while((opt = getopt(argc, argv, "m:p:blh")) != -1) { + switch(opt) { + case 'm': + msize = atoi(optarg); + break; + case 'p': + nprocs = atoi(optarg); + if(nprocs <= 0) { + printf("The number of process should be larger than 0\n"); + exit(0); + } + if(nprocs % 2 != 0) { + printf("The number of process should be even\n"); + exit(0); + } + break; + case 'b': + bw_on = true; + break; + case 'l': + lt_on = true; + break; + case 'h': + print_help(argv); + exit(0); + } + } + + if(!lt_on && !bw_on) { + print_help(argv); + exit(0); + } + + bw = 0; + lt_cnt = 0; + max = total = 0.0; + min = 1000000.0; + + if(lt_on) + Measure_latency(); + + if(bw_on) + Measure_bandwidth(); +} diff --git a/benchmark/socket.c b/benchmark/socket.c new file mode 100644 index 0000000..6945a64 --- /dev/null +++ b/benchmark/socket.c @@ -0,0 +1,362 @@ +/* + * lat_socket.c - socket IPC latency + * + */ + +#include "common.h" + +int nprocs; +int msize; +int lt_cnt; +double min, max, total; +unsigned long long bw; + +bool lt_on, bw_on; + +void Receive(int rfd1, int rfd2, register int size, bool is_lt) +{ + static int bw_cnt = 0; + unsigned long long start; + unsigned long long end; + register char *buf = (char *)malloc(size); + + for(int i = 0; i < WARMUP_TRY + REAL_TRY; i++) { + if(is_lt) { + if (read(rfd1, (void *)&start, sizeof(unsigned long long)) + != sizeof(unsigned long long)) { + perror("(read 1) read/write on socket parent"); + exit(1); + } + } + + if (read(rfd2, buf, size) != size) { + perror("(read 2) read/write on socket parent"); + exit(1); + } + else if(buf[0] == 'r'){ + struct timespec clock; + if(is_lt) { + clock_gettime (CLOCK_REALTIME, &clock); + end = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + + double lt = (double)(end - start) / 1000; +#ifdef DEBUG_ON + printf("latency: %0.4f\n", lt); +#endif + + if(lt > 0) { + lt_cnt++; + total += lt; + if(lt > max) + max = lt; + + if(lt < min) + min = lt; + } + } + else { + bw_cnt++; + if(bw_cnt == 1) { + clock_gettime (CLOCK_REALTIME, &clock); + start = (unsigned long long)clock.tv_sec * NS + + (unsigned long long)clock.tv_nsec; + } + + if(bw_cnt == REAL_TRY) { + clock_gettime (CLOCK_REALTIME, &clock); + end = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + bw = ((unsigned long long)NS * bw_cnt)/(end - start); + printf("bandwidth: %llu (/s)\n", bw); + } + } + } + } + + free(buf); +} + +void Send(int wfd1, int wfd2, register int size, bool is_lt) +{ + register char *cptr = (char *)malloc(size); + + sleep(2); + for(int i = 0; i < WARMUP_TRY + REAL_TRY; i++) { + int wres1, wres2; + struct timespec clock; + + memset(cptr, 0, size); + if(i >= WARMUP_TRY) + cptr[0] = 'r'; + else + cptr[0] = 'w'; + + if(is_lt) { + clock_gettime (CLOCK_REALTIME, &clock); + unsigned long long start = (unsigned long long)clock.tv_sec * NS + +(unsigned long long)clock.tv_nsec; + + wres1 = write(wfd1, (void *)&start, sizeof(unsigned long long)); + if (wres1 != sizeof(unsigned long long)) { + perror("(write 1) read/write on socket child"); + exit(1); + } + } + wres2 = write(wfd2, cptr, size); + if (wres2 != size) { + perror("(write 2) read/write on socket child"); + exit(1); + } + + if(is_lt) { + if(size <= ONE_PAGE_SIZE) + usleep(5000); + else if(size <= 10 * ONE_PAGE_SIZE) + usleep(10000); + else if(size <= 100 * ONE_PAGE_SIZE) + usleep(20000); + else + usleep(40000); + } + } + + free(cptr); +} + +void Measure_bandwidth(void) +{ + int ret; + int returnp[nprocs/2][2]; + int fd[nprocs/2][2]; + int pids[nprocs]; + int ready_fd; + char *ready_ptr; + + ready_fd = shm_open("isready", O_CREAT | O_TRUNC | O_RDWR, 0666); + if(ready_fd == -1) + { + perror("Open"); + return; + } + if(ftruncate(ready_fd, sizeof(char))) { + perror("Ftruncate"); + return; + } + ready_ptr = mmap(0, sizeof(char), PROT_READ | PROT_WRITE, + MAP_SHARED, ready_fd, 0); + if(ready_ptr == MAP_FAILED) { + perror("Mmap"); + return; + } + close(ready_fd); + ready_ptr[0] = "n"; + + for(int i = 0; i < nprocs/2; i++) { + if(pipe(returnp[i]) == -1) { + perror("pipe"); + exit(1); + } + } + + for(int i = 0; i < nprocs/2; i++) { + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd[i]) == -1) { + perror("socketpair"); + exit(1); + } + } + + for(int i = 0; i < nprocs/2; i++) { + if(pipe(returnp[i]) == -1) { + perror("pipe"); + exit(1); + } + } + + if(!cpu_pin(0, getpid())) { + perror("CPU pinning for parent"); + exit(1); + } + + for(int child = 1; child < nprocs; child++) { + int pid = fork(); + switch (pid) { + //child + case 0: + if(!cpu_pin(child, getpid())) { + perror("CPU pinning for child"); + exit(1); + } + + // Wait for parent + while(ready_ptr[0] == "n") { + } + + if(child % 2 == 0) { + Receive(0, fd[child/2][1], msize, false); + close(fd[child/2][1]); + + //send result(bandwidth) to parent + { + int wres; + close(returnp[child/2][0]); + wres = write(returnp[child/2][1], (void *)&bw, sizeof(unsigned long long)); + if (wres != sizeof(unsigned long long)) { + perror("(write return) read/write on pipe sender"); + exit(1); + } + close(returnp[child/2][1]); + } + } + else { + Send(0, fd[child/2][0], msize, false); + close(fd[child/2][0]); + } + exit(0); + case -1: + perror("fork"); + return; + default: + pids[child] = pid; + break; + } + } + + sleep(1); + ready_ptr[0] = "y"; + + Receive(0, fd[0][1], msize, false); + close(fd[0][1]); + for(int child = 1; child < nprocs; child++) { + //receive result(bandwidth) from child(s) + if(child % 2 == 0) { + int rres; + unsigned long long child_bw; + + close(returnp[child/2][1]); + rres = read(returnp[child/2][0], (void *)&child_bw, sizeof(unsigned long long)); + if (rres != sizeof(unsigned long long)) { + perror("(write return) read/write on pipe receiver"); + exit(1); + } + close(returnp[child/2][0]); + bw += child_bw; + } + + waitpid(pids[child], NULL, 0); + } + ret = munmap(ready_ptr, sizeof(bool)); + if (ret != 0) { + perror("munmap"); + exit(1); + } + + ret = shm_unlink("isready"); + if (ret != 0) { + perror("shm unlink"); + //exit(1); + } + printf("Total bandwidth: %llu (/s)\n", bw); +} + +void Measure_latency(void) +{ + int fd1[2], fd2[2]; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd1) == -1) { + perror("socketpair"); + exit(1); + } + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd2) == -1) { + perror("socketpair"); + exit(1); + } + + if(!cpu_pin(0, getpid())) { + perror("CPU pinning for parent"); + exit(1); + } + + int pid = fork(); + switch (pid) { + //child + case 0: + if(!cpu_pin(1, getpid())) { + perror("CPU pinning for child"); + exit(1); + } + Send(fd1[0], fd2[0], msize, true); + close(fd1[0]); + close(fd2[0]); + exit(0); + case -1: + perror("fork"); + return; + default: + Receive(fd1[1], fd2[1], msize, true); + close(fd1[1]); + close(fd2[1]); + printf("min: %0.4f(us), max: %0.4f(us), avg: %0.4f(us)\n", min, max, total/lt_cnt); + waitpid(pid, NULL, 0); + return; + } +} + + int +main(int argc, char **argv) +{ + int opt; + extern char *optarg; + extern int optind; + + nprocs = get_nprocs(); + if(nprocs == 1) + nprocs = 2; + + msize = 3; + lt_on = bw_on = false; + while((opt = getopt(argc, argv, "m:p:blh")) != -1) { + switch(opt) { + case 'm': + msize = atoi(optarg); + break; + case 'p': + nprocs = atoi(optarg); + if(nprocs <= 0) { + printf("The number of process should be larger than 0\n"); + exit(0); + } + if(nprocs % 2 != 0) { + printf("The number of process should be even\n"); + exit(0); + } + break; + case 'b': + bw_on = true; + break; + case 'l': + lt_on = true; + break; + case 'h': + print_help(argv); + exit(0); + } + } + + if(!lt_on && !bw_on) { + print_help(argv); + exit(0); + } + + bw = 0; + lt_cnt = 0; + max = total = 0.0; + min = 1000000.0; + + if(lt_on) + Measure_latency(); + + if(bw_on) + Measure_bandwidth(); +} diff --git a/benchmark/test_pc.sh b/benchmark/test_pc.sh new file mode 100755 index 0000000..a388739 --- /dev/null +++ b/benchmark/test_pc.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +ARCH="armv7l" +USER="owner" +DIR="/home/unsunglee/tizen/output/local/repos/public/$ARCH/RPMS" +PACKAGE=${PWD##*/} +TYPE="benchmark" +VERSION="0.1-1" +RESULT="/tmp/test_result" + +###Build +gbs build -A $ARCH --include + +###Install package +sdb root on +sdb push $DIR/$PACKAGE-$TYPE-$VERSION.$ARCH.rpm /tmp +sdb shell mount -o remount,rw / +sdb shell rpm -ivh /tmp/$PACKAGE-$TYPE-$VERSION.$ARCH.rpm --nodeps --force + +###Running benchmark +sdb push test_target.sh /home/$USER/test.sh +#sdb shell chown #USER:users /dev/shm +echo "##########Running benchmarks" +echo "##########It takes a little bit of time" +sdb shell su - $USER /home/$USER/test.sh +sdb shell rm /home/$USER/test.sh +sdb pull $RESULT . +sdb shell rm $RESULT + diff --git a/benchmark/test_target.sh b/benchmark/test_target.sh new file mode 100755 index 0000000..46d2f87 --- /dev/null +++ b/benchmark/test_target.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +USER="owner" +RESULT="/tmp/test_result" + +#running benchmark and store results in the file +echo "##########Pipe##########" >> $RESULT +pipe -b -l >> $RESULT +echo "" >> $RESULT +echo "##########Socket##########" >> $RESULT +socket -b -l >> $RESULT +echo "" >> $RESULT +echo "##########Shared memory##########" >> $RESULT +sharedmem -b -l >> $RESULT +echo "" >> $RESULT +echo "##########Gdbus##########" >> $RESULT +gdbus -b -l >> $RESULT +echo "" >> $RESULT +echo "##########Libdbus##########" >> $RESULT +libdbus -b -l >> $RESULT +echo "" >> $RESULT diff --git a/packaging/dbus-tools.spec b/packaging/dbus-tools.spec index 4b4b451..d8c3412 100644 --- a/packaging/dbus-tools.spec +++ b/packaging/dbus-tools.spec @@ -6,24 +6,38 @@ License: Apache-2.0, MIT Requires: libxslt-tools cynara Source: %{name}-%{version}.tar.gz Source101: dbus-tools.manifest -BuildArch: noarch +#BuildArch: noarch BuildRequires: autoconf +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(dbus-1) %description This package provides a set of tools for working with D-Bus. It includes: dbuspolicy-checker: a light-weight checker for D-Bus policy files. It checks syntax and semantics, looking for common errors. +benchmark: benchmarks to measure latency and bandwidth of IPC(pipe, shared memory, socket, libdbus, and gdbus). + + +%package benchmark +Summary: IPC benchmark + +%description benchmark +This package provides a set of benchmarks to measure latency and bandwidth of IPC +(pipe, shared memory, socket, libdbus, and gdbus). %prep %setup -q cp %{SOURCE101} . %build +make pushd policychecker autoconf %configure popd +make %install %make_install @@ -35,3 +49,10 @@ popd %license LICENSE.APACHE2.0 LICENSE.MIT %{_bindir}/dbuspolicy-checker %{_datadir}/dbus-tools/policychecker/* + +%files benchmark +%{_bindir}/pipe +%{_bindir}/socket +%{_bindir}/sharedmem +%{_bindir}/gdbus +%{_bindir}/libdbus -- 2.34.1