162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This application is Copyright 2012 Red Hat, Inc. 362306a36Sopenharmony_ci * Doug Ledford <dledford@redhat.com> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * mq_perf_tests is free software: you can redistribute it and/or modify 662306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 762306a36Sopenharmony_ci * the Free Software Foundation, version 3. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * mq_perf_tests is distributed in the hope that it will be useful, 1062306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1162306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1262306a36Sopenharmony_ci * GNU General Public License for more details. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * For the full text of the license, see <http://www.gnu.org/licenses/>. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * mq_perf_tests.c 1762306a36Sopenharmony_ci * Tests various types of message queue workloads, concentrating on those 1862306a36Sopenharmony_ci * situations that invole large message sizes, large message queue depths, 1962306a36Sopenharmony_ci * or both, and reports back useful metrics about kernel message queue 2062306a36Sopenharmony_ci * performance. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci#define _GNU_SOURCE 2462306a36Sopenharmony_ci#include <stdio.h> 2562306a36Sopenharmony_ci#include <stdlib.h> 2662306a36Sopenharmony_ci#include <unistd.h> 2762306a36Sopenharmony_ci#include <fcntl.h> 2862306a36Sopenharmony_ci#include <string.h> 2962306a36Sopenharmony_ci#include <limits.h> 3062306a36Sopenharmony_ci#include <errno.h> 3162306a36Sopenharmony_ci#include <signal.h> 3262306a36Sopenharmony_ci#include <pthread.h> 3362306a36Sopenharmony_ci#include <sched.h> 3462306a36Sopenharmony_ci#include <sys/types.h> 3562306a36Sopenharmony_ci#include <sys/time.h> 3662306a36Sopenharmony_ci#include <sys/resource.h> 3762306a36Sopenharmony_ci#include <sys/stat.h> 3862306a36Sopenharmony_ci#include <sys/param.h> 3962306a36Sopenharmony_ci#include <mqueue.h> 4062306a36Sopenharmony_ci#include <popt.h> 4162306a36Sopenharmony_ci#include <error.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include "../kselftest.h" 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic char *usage = 4662306a36Sopenharmony_ci"Usage:\n" 4762306a36Sopenharmony_ci" %s [-c #[,#..] -f] path\n" 4862306a36Sopenharmony_ci"\n" 4962306a36Sopenharmony_ci" -c # Skip most tests and go straight to a high queue depth test\n" 5062306a36Sopenharmony_ci" and then run that test continuously (useful for running at\n" 5162306a36Sopenharmony_ci" the same time as some other workload to see how much the\n" 5262306a36Sopenharmony_ci" cache thrashing caused by adding messages to a very deep\n" 5362306a36Sopenharmony_ci" queue impacts the performance of other programs). The number\n" 5462306a36Sopenharmony_ci" indicates which CPU core we should bind the process to during\n" 5562306a36Sopenharmony_ci" the run. If you have more than one physical CPU, then you\n" 5662306a36Sopenharmony_ci" will need one copy per physical CPU package, and you should\n" 5762306a36Sopenharmony_ci" specify the CPU cores to pin ourself to via a comma separated\n" 5862306a36Sopenharmony_ci" list of CPU values.\n" 5962306a36Sopenharmony_ci" -f Only usable with continuous mode. Pin ourself to the CPUs\n" 6062306a36Sopenharmony_ci" as requested, then instead of looping doing a high mq\n" 6162306a36Sopenharmony_ci" workload, just busy loop. This will allow us to lock up a\n" 6262306a36Sopenharmony_ci" single CPU just like we normally would, but without actually\n" 6362306a36Sopenharmony_ci" thrashing the CPU cache. This is to make it easier to get\n" 6462306a36Sopenharmony_ci" comparable numbers from some other workload running on the\n" 6562306a36Sopenharmony_ci" other CPUs. One set of numbers with # CPUs locked up running\n" 6662306a36Sopenharmony_ci" an mq workload, and another set of numbers with those same\n" 6762306a36Sopenharmony_ci" CPUs locked away from the test workload, but not doing\n" 6862306a36Sopenharmony_ci" anything to trash the cache like the mq workload might.\n" 6962306a36Sopenharmony_ci" path Path name of the message queue to create\n" 7062306a36Sopenharmony_ci"\n" 7162306a36Sopenharmony_ci" Note: this program must be run as root in order to enable all tests\n" 7262306a36Sopenharmony_ci"\n"; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cichar *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max"; 7562306a36Sopenharmony_cichar *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max"; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define MAX_CPUS 64 7862306a36Sopenharmony_cichar *cpu_option_string; 7962306a36Sopenharmony_ciint cpus_to_pin[MAX_CPUS]; 8062306a36Sopenharmony_ciint num_cpus_to_pin; 8162306a36Sopenharmony_cipthread_t cpu_threads[MAX_CPUS]; 8262306a36Sopenharmony_cipthread_t main_thread; 8362306a36Sopenharmony_cicpu_set_t *cpu_set; 8462306a36Sopenharmony_ciint cpu_set_size; 8562306a36Sopenharmony_ciint cpus_online; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define MSG_SIZE 16 8862306a36Sopenharmony_ci#define TEST1_LOOPS 10000000 8962306a36Sopenharmony_ci#define TEST2_LOOPS 100000 9062306a36Sopenharmony_ciint continuous_mode; 9162306a36Sopenharmony_ciint continuous_mode_fake; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistruct rlimit saved_limits, cur_limits; 9462306a36Sopenharmony_ciint saved_max_msgs, saved_max_msgsize; 9562306a36Sopenharmony_ciint cur_max_msgs, cur_max_msgsize; 9662306a36Sopenharmony_ciFILE *max_msgs, *max_msgsize; 9762306a36Sopenharmony_ciint cur_nice; 9862306a36Sopenharmony_cichar *queue_path = "/mq_perf_tests"; 9962306a36Sopenharmony_cimqd_t queue = -1; 10062306a36Sopenharmony_cistruct mq_attr result; 10162306a36Sopenharmony_ciint mq_prio_max; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ciconst struct poptOption options[] = { 10462306a36Sopenharmony_ci { 10562306a36Sopenharmony_ci .longName = "continuous", 10662306a36Sopenharmony_ci .shortName = 'c', 10762306a36Sopenharmony_ci .argInfo = POPT_ARG_STRING, 10862306a36Sopenharmony_ci .arg = &cpu_option_string, 10962306a36Sopenharmony_ci .val = 'c', 11062306a36Sopenharmony_ci .descrip = "Run continuous tests at a high queue depth in " 11162306a36Sopenharmony_ci "order to test the effects of cache thrashing on " 11262306a36Sopenharmony_ci "other tasks on the system. This test is intended " 11362306a36Sopenharmony_ci "to be run on one core of each physical CPU while " 11462306a36Sopenharmony_ci "some other CPU intensive task is run on all the other " 11562306a36Sopenharmony_ci "cores of that same physical CPU and the other task " 11662306a36Sopenharmony_ci "is timed. It is assumed that the process of adding " 11762306a36Sopenharmony_ci "messages to the message queue in a tight loop will " 11862306a36Sopenharmony_ci "impact that other task to some degree. Once the " 11962306a36Sopenharmony_ci "tests are performed in this way, you should then " 12062306a36Sopenharmony_ci "re-run the tests using fake mode in order to check " 12162306a36Sopenharmony_ci "the difference in time required to perform the CPU " 12262306a36Sopenharmony_ci "intensive task", 12362306a36Sopenharmony_ci .argDescrip = "cpu[,cpu]", 12462306a36Sopenharmony_ci }, 12562306a36Sopenharmony_ci { 12662306a36Sopenharmony_ci .longName = "fake", 12762306a36Sopenharmony_ci .shortName = 'f', 12862306a36Sopenharmony_ci .argInfo = POPT_ARG_NONE, 12962306a36Sopenharmony_ci .arg = &continuous_mode_fake, 13062306a36Sopenharmony_ci .val = 0, 13162306a36Sopenharmony_ci .descrip = "Tie up the CPUs that we would normally tie up in" 13262306a36Sopenharmony_ci "continuous mode, but don't actually do any mq stuff, " 13362306a36Sopenharmony_ci "just keep the CPU busy so it can't be used to process " 13462306a36Sopenharmony_ci "system level tasks as this would free up resources on " 13562306a36Sopenharmony_ci "the other CPU cores and skew the comparison between " 13662306a36Sopenharmony_ci "the no-mqueue work and mqueue work tests", 13762306a36Sopenharmony_ci .argDescrip = NULL, 13862306a36Sopenharmony_ci }, 13962306a36Sopenharmony_ci { 14062306a36Sopenharmony_ci .longName = "path", 14162306a36Sopenharmony_ci .shortName = 'p', 14262306a36Sopenharmony_ci .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, 14362306a36Sopenharmony_ci .arg = &queue_path, 14462306a36Sopenharmony_ci .val = 'p', 14562306a36Sopenharmony_ci .descrip = "The name of the path to use in the mqueue " 14662306a36Sopenharmony_ci "filesystem for our tests", 14762306a36Sopenharmony_ci .argDescrip = "pathname", 14862306a36Sopenharmony_ci }, 14962306a36Sopenharmony_ci POPT_AUTOHELP 15062306a36Sopenharmony_ci POPT_TABLEEND 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic inline void __set(FILE *stream, int value, char *err_msg); 15462306a36Sopenharmony_civoid shutdown(int exit_val, char *err_cause, int line_no); 15562306a36Sopenharmony_civoid sig_action_SIGUSR1(int signum, siginfo_t *info, void *context); 15662306a36Sopenharmony_civoid sig_action(int signum, siginfo_t *info, void *context); 15762306a36Sopenharmony_cistatic inline int get(FILE *stream); 15862306a36Sopenharmony_cistatic inline void set(FILE *stream, int value); 15962306a36Sopenharmony_cistatic inline int try_set(FILE *stream, int value); 16062306a36Sopenharmony_cistatic inline void getr(int type, struct rlimit *rlim); 16162306a36Sopenharmony_cistatic inline void setr(int type, struct rlimit *rlim); 16262306a36Sopenharmony_cistatic inline void open_queue(struct mq_attr *attr); 16362306a36Sopenharmony_civoid increase_limits(void); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic inline void __set(FILE *stream, int value, char *err_msg) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci rewind(stream); 16862306a36Sopenharmony_ci if (fprintf(stream, "%d", value) < 0) 16962306a36Sopenharmony_ci perror(err_msg); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_civoid shutdown(int exit_val, char *err_cause, int line_no) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci static int in_shutdown = 0; 17662306a36Sopenharmony_ci int errno_at_shutdown = errno; 17762306a36Sopenharmony_ci int i; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* In case we get called by multiple threads or from an sighandler */ 18062306a36Sopenharmony_ci if (in_shutdown++) 18162306a36Sopenharmony_ci return; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* Free the cpu_set allocated using CPU_ALLOC in main function */ 18462306a36Sopenharmony_ci CPU_FREE(cpu_set); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci for (i = 0; i < num_cpus_to_pin; i++) 18762306a36Sopenharmony_ci if (cpu_threads[i]) { 18862306a36Sopenharmony_ci pthread_kill(cpu_threads[i], SIGUSR1); 18962306a36Sopenharmony_ci pthread_join(cpu_threads[i], NULL); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (queue != -1) 19362306a36Sopenharmony_ci if (mq_close(queue)) 19462306a36Sopenharmony_ci perror("mq_close() during shutdown"); 19562306a36Sopenharmony_ci if (queue_path) 19662306a36Sopenharmony_ci /* 19762306a36Sopenharmony_ci * Be silent if this fails, if we cleaned up already it's 19862306a36Sopenharmony_ci * expected to fail 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ci mq_unlink(queue_path); 20162306a36Sopenharmony_ci if (saved_max_msgs) 20262306a36Sopenharmony_ci __set(max_msgs, saved_max_msgs, 20362306a36Sopenharmony_ci "failed to restore saved_max_msgs"); 20462306a36Sopenharmony_ci if (saved_max_msgsize) 20562306a36Sopenharmony_ci __set(max_msgsize, saved_max_msgsize, 20662306a36Sopenharmony_ci "failed to restore saved_max_msgsize"); 20762306a36Sopenharmony_ci if (exit_val) 20862306a36Sopenharmony_ci error(exit_val, errno_at_shutdown, "%s at %d", 20962306a36Sopenharmony_ci err_cause, line_no); 21062306a36Sopenharmony_ci exit(0); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_civoid sig_action_SIGUSR1(int signum, siginfo_t *info, void *context) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci if (pthread_self() != main_thread) 21662306a36Sopenharmony_ci pthread_exit(0); 21762306a36Sopenharmony_ci else { 21862306a36Sopenharmony_ci fprintf(stderr, "Caught signal %d in SIGUSR1 handler, " 21962306a36Sopenharmony_ci "exiting\n", signum); 22062306a36Sopenharmony_ci shutdown(0, "", 0); 22162306a36Sopenharmony_ci fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n"); 22262306a36Sopenharmony_ci exit(0); 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_civoid sig_action(int signum, siginfo_t *info, void *context) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci if (pthread_self() != main_thread) 22962306a36Sopenharmony_ci pthread_kill(main_thread, signum); 23062306a36Sopenharmony_ci else { 23162306a36Sopenharmony_ci fprintf(stderr, "Caught signal %d, exiting\n", signum); 23262306a36Sopenharmony_ci shutdown(0, "", 0); 23362306a36Sopenharmony_ci fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n"); 23462306a36Sopenharmony_ci exit(0); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic inline int get(FILE *stream) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci int value; 24162306a36Sopenharmony_ci rewind(stream); 24262306a36Sopenharmony_ci if (fscanf(stream, "%d", &value) != 1) 24362306a36Sopenharmony_ci shutdown(4, "Error reading /proc entry", __LINE__); 24462306a36Sopenharmony_ci return value; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic inline void set(FILE *stream, int value) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci int new_value; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci rewind(stream); 25262306a36Sopenharmony_ci if (fprintf(stream, "%d", value) < 0) 25362306a36Sopenharmony_ci return shutdown(5, "Failed writing to /proc file", __LINE__); 25462306a36Sopenharmony_ci new_value = get(stream); 25562306a36Sopenharmony_ci if (new_value != value) 25662306a36Sopenharmony_ci return shutdown(5, "We didn't get what we wrote to /proc back", 25762306a36Sopenharmony_ci __LINE__); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic inline int try_set(FILE *stream, int value) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci int new_value; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci rewind(stream); 26562306a36Sopenharmony_ci fprintf(stream, "%d", value); 26662306a36Sopenharmony_ci new_value = get(stream); 26762306a36Sopenharmony_ci return new_value == value; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic inline void getr(int type, struct rlimit *rlim) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci if (getrlimit(type, rlim)) 27362306a36Sopenharmony_ci shutdown(6, "getrlimit()", __LINE__); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic inline void setr(int type, struct rlimit *rlim) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci if (setrlimit(type, rlim)) 27962306a36Sopenharmony_ci shutdown(7, "setrlimit()", __LINE__); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/** 28362306a36Sopenharmony_ci * open_queue - open the global queue for testing 28462306a36Sopenharmony_ci * @attr - An attr struct specifying the desired queue traits 28562306a36Sopenharmony_ci * @result - An attr struct that lists the actual traits the queue has 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * This open is not allowed to fail, failure will result in an orderly 28862306a36Sopenharmony_ci * shutdown of the program. The global queue_path is used to set what 28962306a36Sopenharmony_ci * queue to open, the queue descriptor is saved in the global queue 29062306a36Sopenharmony_ci * variable. 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_cistatic inline void open_queue(struct mq_attr *attr) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci int flags = O_RDWR | O_EXCL | O_CREAT | O_NONBLOCK; 29562306a36Sopenharmony_ci int perms = DEFFILEMODE; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci queue = mq_open(queue_path, flags, perms, attr); 29862306a36Sopenharmony_ci if (queue == -1) 29962306a36Sopenharmony_ci shutdown(1, "mq_open()", __LINE__); 30062306a36Sopenharmony_ci if (mq_getattr(queue, &result)) 30162306a36Sopenharmony_ci shutdown(1, "mq_getattr()", __LINE__); 30262306a36Sopenharmony_ci printf("\n\tQueue %s created:\n", queue_path); 30362306a36Sopenharmony_ci printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ? 30462306a36Sopenharmony_ci "O_NONBLOCK" : "(null)"); 30562306a36Sopenharmony_ci printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg); 30662306a36Sopenharmony_ci printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize); 30762306a36Sopenharmony_ci printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_civoid *fake_cont_thread(void *arg) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci int i; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci for (i = 0; i < num_cpus_to_pin; i++) 31562306a36Sopenharmony_ci if (cpu_threads[i] == pthread_self()) 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci printf("\tStarted fake continuous mode thread %d on CPU %d\n", i, 31862306a36Sopenharmony_ci cpus_to_pin[i]); 31962306a36Sopenharmony_ci while (1) 32062306a36Sopenharmony_ci ; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_civoid *cont_thread(void *arg) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci char buff[MSG_SIZE]; 32662306a36Sopenharmony_ci int i, priority; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci for (i = 0; i < num_cpus_to_pin; i++) 32962306a36Sopenharmony_ci if (cpu_threads[i] == pthread_self()) 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci printf("\tStarted continuous mode thread %d on CPU %d\n", i, 33262306a36Sopenharmony_ci cpus_to_pin[i]); 33362306a36Sopenharmony_ci while (1) { 33462306a36Sopenharmony_ci while (mq_send(queue, buff, sizeof(buff), 0) == 0) 33562306a36Sopenharmony_ci ; 33662306a36Sopenharmony_ci mq_receive(queue, buff, sizeof(buff), &priority); 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci#define drain_queue() \ 34162306a36Sopenharmony_ci while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE) 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci#define do_untimed_send() \ 34462306a36Sopenharmony_ci do { \ 34562306a36Sopenharmony_ci if (mq_send(queue, buff, MSG_SIZE, prio_out)) \ 34662306a36Sopenharmony_ci shutdown(3, "Test send failure", __LINE__); \ 34762306a36Sopenharmony_ci } while (0) 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci#define do_send_recv() \ 35062306a36Sopenharmony_ci do { \ 35162306a36Sopenharmony_ci clock_gettime(clock, &start); \ 35262306a36Sopenharmony_ci if (mq_send(queue, buff, MSG_SIZE, prio_out)) \ 35362306a36Sopenharmony_ci shutdown(3, "Test send failure", __LINE__); \ 35462306a36Sopenharmony_ci clock_gettime(clock, &middle); \ 35562306a36Sopenharmony_ci if (mq_receive(queue, buff, MSG_SIZE, &prio_in) != MSG_SIZE) \ 35662306a36Sopenharmony_ci shutdown(3, "Test receive failure", __LINE__); \ 35762306a36Sopenharmony_ci clock_gettime(clock, &end); \ 35862306a36Sopenharmony_ci nsec = ((middle.tv_sec - start.tv_sec) * 1000000000) + \ 35962306a36Sopenharmony_ci (middle.tv_nsec - start.tv_nsec); \ 36062306a36Sopenharmony_ci send_total.tv_nsec += nsec; \ 36162306a36Sopenharmony_ci if (send_total.tv_nsec >= 1000000000) { \ 36262306a36Sopenharmony_ci send_total.tv_sec++; \ 36362306a36Sopenharmony_ci send_total.tv_nsec -= 1000000000; \ 36462306a36Sopenharmony_ci } \ 36562306a36Sopenharmony_ci nsec = ((end.tv_sec - middle.tv_sec) * 1000000000) + \ 36662306a36Sopenharmony_ci (end.tv_nsec - middle.tv_nsec); \ 36762306a36Sopenharmony_ci recv_total.tv_nsec += nsec; \ 36862306a36Sopenharmony_ci if (recv_total.tv_nsec >= 1000000000) { \ 36962306a36Sopenharmony_ci recv_total.tv_sec++; \ 37062306a36Sopenharmony_ci recv_total.tv_nsec -= 1000000000; \ 37162306a36Sopenharmony_ci } \ 37262306a36Sopenharmony_ci } while (0) 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistruct test { 37562306a36Sopenharmony_ci char *desc; 37662306a36Sopenharmony_ci void (*func)(int *); 37762306a36Sopenharmony_ci}; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_civoid const_prio(int *prio) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci return; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_civoid inc_prio(int *prio) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci if (++*prio == mq_prio_max) 38762306a36Sopenharmony_ci *prio = 0; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_civoid dec_prio(int *prio) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci if (--*prio < 0) 39362306a36Sopenharmony_ci *prio = mq_prio_max - 1; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_civoid random_prio(int *prio) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci *prio = random() % mq_prio_max; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistruct test test2[] = { 40262306a36Sopenharmony_ci {"\n\tTest #2a: Time send/recv message, queue full, constant prio\n", 40362306a36Sopenharmony_ci const_prio}, 40462306a36Sopenharmony_ci {"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n", 40562306a36Sopenharmony_ci inc_prio}, 40662306a36Sopenharmony_ci {"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n", 40762306a36Sopenharmony_ci dec_prio}, 40862306a36Sopenharmony_ci {"\n\tTest #2d: Time send/recv message, queue full, random prio\n", 40962306a36Sopenharmony_ci random_prio}, 41062306a36Sopenharmony_ci {NULL, NULL} 41162306a36Sopenharmony_ci}; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/** 41462306a36Sopenharmony_ci * Tests to perform (all done with MSG_SIZE messages): 41562306a36Sopenharmony_ci * 41662306a36Sopenharmony_ci * 1) Time to add/remove message with 0 messages on queue 41762306a36Sopenharmony_ci * 1a) with constant prio 41862306a36Sopenharmony_ci * 2) Time to add/remove message when queue close to capacity: 41962306a36Sopenharmony_ci * 2a) with constant prio 42062306a36Sopenharmony_ci * 2b) with increasing prio 42162306a36Sopenharmony_ci * 2c) with decreasing prio 42262306a36Sopenharmony_ci * 2d) with random prio 42362306a36Sopenharmony_ci * 3) Test limits of priorities honored (double check _SC_MQ_PRIO_MAX) 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_civoid *perf_test_thread(void *arg) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci char buff[MSG_SIZE]; 42862306a36Sopenharmony_ci int prio_out, prio_in; 42962306a36Sopenharmony_ci int i; 43062306a36Sopenharmony_ci clockid_t clock; 43162306a36Sopenharmony_ci pthread_t *t; 43262306a36Sopenharmony_ci struct timespec res, start, middle, end, send_total, recv_total; 43362306a36Sopenharmony_ci unsigned long long nsec; 43462306a36Sopenharmony_ci struct test *cur_test; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci t = &cpu_threads[0]; 43762306a36Sopenharmony_ci printf("\n\tStarted mqueue performance test thread on CPU %d\n", 43862306a36Sopenharmony_ci cpus_to_pin[0]); 43962306a36Sopenharmony_ci mq_prio_max = sysconf(_SC_MQ_PRIO_MAX); 44062306a36Sopenharmony_ci if (mq_prio_max == -1) 44162306a36Sopenharmony_ci shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__); 44262306a36Sopenharmony_ci if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0) 44362306a36Sopenharmony_ci shutdown(2, "pthread_getcpuclockid", __LINE__); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (clock_getres(clock, &res)) 44662306a36Sopenharmony_ci shutdown(2, "clock_getres()", __LINE__); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max); 44962306a36Sopenharmony_ci printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec, 45062306a36Sopenharmony_ci res.tv_nsec > 1 ? "s" : ""); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci printf("\n\tTest #1: Time send/recv message, queue empty\n"); 45562306a36Sopenharmony_ci printf("\t\t(%d iterations)\n", TEST1_LOOPS); 45662306a36Sopenharmony_ci prio_out = 0; 45762306a36Sopenharmony_ci send_total.tv_sec = 0; 45862306a36Sopenharmony_ci send_total.tv_nsec = 0; 45962306a36Sopenharmony_ci recv_total.tv_sec = 0; 46062306a36Sopenharmony_ci recv_total.tv_nsec = 0; 46162306a36Sopenharmony_ci for (i = 0; i < TEST1_LOOPS; i++) 46262306a36Sopenharmony_ci do_send_recv(); 46362306a36Sopenharmony_ci printf("\t\tSend msg:\t\t\t%ld.%lus total time\n", 46462306a36Sopenharmony_ci send_total.tv_sec, send_total.tv_nsec); 46562306a36Sopenharmony_ci nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + 46662306a36Sopenharmony_ci send_total.tv_nsec) / TEST1_LOOPS; 46762306a36Sopenharmony_ci printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); 46862306a36Sopenharmony_ci printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n", 46962306a36Sopenharmony_ci recv_total.tv_sec, recv_total.tv_nsec); 47062306a36Sopenharmony_ci nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + 47162306a36Sopenharmony_ci recv_total.tv_nsec) / TEST1_LOOPS; 47262306a36Sopenharmony_ci printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci for (cur_test = test2; cur_test->desc != NULL; cur_test++) { 47662306a36Sopenharmony_ci printf("%s:\n", cur_test->desc); 47762306a36Sopenharmony_ci printf("\t\t(%d iterations)\n", TEST2_LOOPS); 47862306a36Sopenharmony_ci prio_out = 0; 47962306a36Sopenharmony_ci send_total.tv_sec = 0; 48062306a36Sopenharmony_ci send_total.tv_nsec = 0; 48162306a36Sopenharmony_ci recv_total.tv_sec = 0; 48262306a36Sopenharmony_ci recv_total.tv_nsec = 0; 48362306a36Sopenharmony_ci printf("\t\tFilling queue..."); 48462306a36Sopenharmony_ci fflush(stdout); 48562306a36Sopenharmony_ci clock_gettime(clock, &start); 48662306a36Sopenharmony_ci for (i = 0; i < result.mq_maxmsg - 1; i++) { 48762306a36Sopenharmony_ci do_untimed_send(); 48862306a36Sopenharmony_ci cur_test->func(&prio_out); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci clock_gettime(clock, &end); 49162306a36Sopenharmony_ci nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) * 49262306a36Sopenharmony_ci 1000000000) + (end.tv_nsec - start.tv_nsec); 49362306a36Sopenharmony_ci printf("done.\t\t%lld.%llds\n", nsec / 1000000000, 49462306a36Sopenharmony_ci nsec % 1000000000); 49562306a36Sopenharmony_ci printf("\t\tTesting..."); 49662306a36Sopenharmony_ci fflush(stdout); 49762306a36Sopenharmony_ci for (i = 0; i < TEST2_LOOPS; i++) { 49862306a36Sopenharmony_ci do_send_recv(); 49962306a36Sopenharmony_ci cur_test->func(&prio_out); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci printf("done.\n"); 50262306a36Sopenharmony_ci printf("\t\tSend msg:\t\t\t%ld.%lus total time\n", 50362306a36Sopenharmony_ci send_total.tv_sec, send_total.tv_nsec); 50462306a36Sopenharmony_ci nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + 50562306a36Sopenharmony_ci send_total.tv_nsec) / TEST2_LOOPS; 50662306a36Sopenharmony_ci printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); 50762306a36Sopenharmony_ci printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n", 50862306a36Sopenharmony_ci recv_total.tv_sec, recv_total.tv_nsec); 50962306a36Sopenharmony_ci nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + 51062306a36Sopenharmony_ci recv_total.tv_nsec) / TEST2_LOOPS; 51162306a36Sopenharmony_ci printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); 51262306a36Sopenharmony_ci printf("\t\tDraining queue..."); 51362306a36Sopenharmony_ci fflush(stdout); 51462306a36Sopenharmony_ci clock_gettime(clock, &start); 51562306a36Sopenharmony_ci drain_queue(); 51662306a36Sopenharmony_ci clock_gettime(clock, &end); 51762306a36Sopenharmony_ci nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) * 51862306a36Sopenharmony_ci 1000000000) + (end.tv_nsec - start.tv_nsec); 51962306a36Sopenharmony_ci printf("done.\t\t%lld.%llds\n", nsec / 1000000000, 52062306a36Sopenharmony_ci nsec % 1000000000); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_civoid increase_limits(void) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci cur_limits.rlim_cur = RLIM_INFINITY; 52862306a36Sopenharmony_ci cur_limits.rlim_max = RLIM_INFINITY; 52962306a36Sopenharmony_ci setr(RLIMIT_MSGQUEUE, &cur_limits); 53062306a36Sopenharmony_ci while (try_set(max_msgs, cur_max_msgs += 10)) 53162306a36Sopenharmony_ci ; 53262306a36Sopenharmony_ci cur_max_msgs = get(max_msgs); 53362306a36Sopenharmony_ci while (try_set(max_msgsize, cur_max_msgsize += 1024)) 53462306a36Sopenharmony_ci ; 53562306a36Sopenharmony_ci cur_max_msgsize = get(max_msgsize); 53662306a36Sopenharmony_ci if (setpriority(PRIO_PROCESS, 0, -20) != 0) 53762306a36Sopenharmony_ci shutdown(2, "setpriority()", __LINE__); 53862306a36Sopenharmony_ci cur_nice = -20; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ciint main(int argc, char *argv[]) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct mq_attr attr; 54462306a36Sopenharmony_ci char *option, *next_option; 54562306a36Sopenharmony_ci int i, cpu, rc; 54662306a36Sopenharmony_ci struct sigaction sa; 54762306a36Sopenharmony_ci poptContext popt_context; 54862306a36Sopenharmony_ci void *retval; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci main_thread = pthread_self(); 55162306a36Sopenharmony_ci num_cpus_to_pin = 0; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (sysconf(_SC_NPROCESSORS_ONLN) == -1) { 55462306a36Sopenharmony_ci perror("sysconf(_SC_NPROCESSORS_ONLN)"); 55562306a36Sopenharmony_ci exit(1); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (getuid() != 0) 55962306a36Sopenharmony_ci ksft_exit_skip("Not running as root, but almost all tests " 56062306a36Sopenharmony_ci "require root in order to modify\nsystem settings. " 56162306a36Sopenharmony_ci "Exiting.\n"); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci cpus_online = MIN(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN)); 56462306a36Sopenharmony_ci cpu_set = CPU_ALLOC(cpus_online); 56562306a36Sopenharmony_ci if (cpu_set == NULL) { 56662306a36Sopenharmony_ci perror("CPU_ALLOC()"); 56762306a36Sopenharmony_ci exit(1); 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci cpu_set_size = CPU_ALLOC_SIZE(cpus_online); 57062306a36Sopenharmony_ci CPU_ZERO_S(cpu_set_size, cpu_set); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci popt_context = poptGetContext(NULL, argc, (const char **)argv, 57362306a36Sopenharmony_ci options, 0); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci while ((rc = poptGetNextOpt(popt_context)) > 0) { 57662306a36Sopenharmony_ci switch (rc) { 57762306a36Sopenharmony_ci case 'c': 57862306a36Sopenharmony_ci continuous_mode = 1; 57962306a36Sopenharmony_ci option = cpu_option_string; 58062306a36Sopenharmony_ci do { 58162306a36Sopenharmony_ci next_option = strchr(option, ','); 58262306a36Sopenharmony_ci if (next_option) 58362306a36Sopenharmony_ci *next_option = '\0'; 58462306a36Sopenharmony_ci cpu = atoi(option); 58562306a36Sopenharmony_ci if (cpu >= cpus_online) 58662306a36Sopenharmony_ci fprintf(stderr, "CPU %d exceeds " 58762306a36Sopenharmony_ci "cpus online, ignoring.\n", 58862306a36Sopenharmony_ci cpu); 58962306a36Sopenharmony_ci else 59062306a36Sopenharmony_ci cpus_to_pin[num_cpus_to_pin++] = cpu; 59162306a36Sopenharmony_ci if (next_option) 59262306a36Sopenharmony_ci option = ++next_option; 59362306a36Sopenharmony_ci } while (next_option && num_cpus_to_pin < MAX_CPUS); 59462306a36Sopenharmony_ci /* Double check that they didn't give us the same CPU 59562306a36Sopenharmony_ci * more than once */ 59662306a36Sopenharmony_ci for (cpu = 0; cpu < num_cpus_to_pin; cpu++) { 59762306a36Sopenharmony_ci if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size, 59862306a36Sopenharmony_ci cpu_set)) { 59962306a36Sopenharmony_ci fprintf(stderr, "Any given CPU may " 60062306a36Sopenharmony_ci "only be given once.\n"); 60162306a36Sopenharmony_ci goto err_code; 60262306a36Sopenharmony_ci } else 60362306a36Sopenharmony_ci CPU_SET_S(cpus_to_pin[cpu], 60462306a36Sopenharmony_ci cpu_set_size, cpu_set); 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci case 'p': 60862306a36Sopenharmony_ci /* 60962306a36Sopenharmony_ci * Although we can create a msg queue with a 61062306a36Sopenharmony_ci * non-absolute path name, unlink will fail. So, 61162306a36Sopenharmony_ci * if the name doesn't start with a /, add one 61262306a36Sopenharmony_ci * when we save it. 61362306a36Sopenharmony_ci */ 61462306a36Sopenharmony_ci option = queue_path; 61562306a36Sopenharmony_ci if (*option != '/') { 61662306a36Sopenharmony_ci queue_path = malloc(strlen(option) + 2); 61762306a36Sopenharmony_ci if (!queue_path) { 61862306a36Sopenharmony_ci perror("malloc()"); 61962306a36Sopenharmony_ci goto err_code; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci queue_path[0] = '/'; 62262306a36Sopenharmony_ci queue_path[1] = 0; 62362306a36Sopenharmony_ci strcat(queue_path, option); 62462306a36Sopenharmony_ci free(option); 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci break; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (continuous_mode && num_cpus_to_pin == 0) { 63162306a36Sopenharmony_ci fprintf(stderr, "Must pass at least one CPU to continuous " 63262306a36Sopenharmony_ci "mode.\n"); 63362306a36Sopenharmony_ci poptPrintUsage(popt_context, stderr, 0); 63462306a36Sopenharmony_ci goto err_code; 63562306a36Sopenharmony_ci } else if (!continuous_mode) { 63662306a36Sopenharmony_ci num_cpus_to_pin = 1; 63762306a36Sopenharmony_ci cpus_to_pin[0] = cpus_online - 1; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci max_msgs = fopen(MAX_MSGS, "r+"); 64162306a36Sopenharmony_ci max_msgsize = fopen(MAX_MSGSIZE, "r+"); 64262306a36Sopenharmony_ci if (!max_msgs) 64362306a36Sopenharmony_ci shutdown(2, "Failed to open msg_max", __LINE__); 64462306a36Sopenharmony_ci if (!max_msgsize) 64562306a36Sopenharmony_ci shutdown(2, "Failed to open msgsize_max", __LINE__); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* Load up the current system values for everything we can */ 64862306a36Sopenharmony_ci getr(RLIMIT_MSGQUEUE, &saved_limits); 64962306a36Sopenharmony_ci cur_limits = saved_limits; 65062306a36Sopenharmony_ci saved_max_msgs = cur_max_msgs = get(max_msgs); 65162306a36Sopenharmony_ci saved_max_msgsize = cur_max_msgsize = get(max_msgsize); 65262306a36Sopenharmony_ci errno = 0; 65362306a36Sopenharmony_ci cur_nice = getpriority(PRIO_PROCESS, 0); 65462306a36Sopenharmony_ci if (errno) 65562306a36Sopenharmony_ci shutdown(2, "getpriority()", __LINE__); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Tell the user our initial state */ 65862306a36Sopenharmony_ci printf("\nInitial system state:\n"); 65962306a36Sopenharmony_ci printf("\tUsing queue path:\t\t\t%s\n", queue_path); 66062306a36Sopenharmony_ci printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n", 66162306a36Sopenharmony_ci (long) saved_limits.rlim_cur); 66262306a36Sopenharmony_ci printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n", 66362306a36Sopenharmony_ci (long) saved_limits.rlim_max); 66462306a36Sopenharmony_ci printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize); 66562306a36Sopenharmony_ci printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs); 66662306a36Sopenharmony_ci printf("\tNice value:\t\t\t\t%d\n", cur_nice); 66762306a36Sopenharmony_ci printf("\n"); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci increase_limits(); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci printf("Adjusted system state for testing:\n"); 67262306a36Sopenharmony_ci if (cur_limits.rlim_cur == RLIM_INFINITY) { 67362306a36Sopenharmony_ci printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n"); 67462306a36Sopenharmony_ci printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n"); 67562306a36Sopenharmony_ci } else { 67662306a36Sopenharmony_ci printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n", 67762306a36Sopenharmony_ci (long) cur_limits.rlim_cur); 67862306a36Sopenharmony_ci printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n", 67962306a36Sopenharmony_ci (long) cur_limits.rlim_max); 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize); 68262306a36Sopenharmony_ci printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs); 68362306a36Sopenharmony_ci printf("\tNice value:\t\t\t\t%d\n", cur_nice); 68462306a36Sopenharmony_ci printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ? 68562306a36Sopenharmony_ci (continuous_mode_fake ? "fake mode" : "enabled") : 68662306a36Sopenharmony_ci "disabled"); 68762306a36Sopenharmony_ci printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]); 68862306a36Sopenharmony_ci for (cpu = 1; cpu < num_cpus_to_pin; cpu++) 68962306a36Sopenharmony_ci printf(",%d", cpus_to_pin[cpu]); 69062306a36Sopenharmony_ci printf("\n"); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci sa.sa_sigaction = sig_action_SIGUSR1; 69362306a36Sopenharmony_ci sigemptyset(&sa.sa_mask); 69462306a36Sopenharmony_ci sigaddset(&sa.sa_mask, SIGHUP); 69562306a36Sopenharmony_ci sigaddset(&sa.sa_mask, SIGINT); 69662306a36Sopenharmony_ci sigaddset(&sa.sa_mask, SIGQUIT); 69762306a36Sopenharmony_ci sigaddset(&sa.sa_mask, SIGTERM); 69862306a36Sopenharmony_ci sa.sa_flags = SA_SIGINFO; 69962306a36Sopenharmony_ci if (sigaction(SIGUSR1, &sa, NULL) == -1) 70062306a36Sopenharmony_ci shutdown(1, "sigaction(SIGUSR1)", __LINE__); 70162306a36Sopenharmony_ci sa.sa_sigaction = sig_action; 70262306a36Sopenharmony_ci if (sigaction(SIGHUP, &sa, NULL) == -1) 70362306a36Sopenharmony_ci shutdown(1, "sigaction(SIGHUP)", __LINE__); 70462306a36Sopenharmony_ci if (sigaction(SIGINT, &sa, NULL) == -1) 70562306a36Sopenharmony_ci shutdown(1, "sigaction(SIGINT)", __LINE__); 70662306a36Sopenharmony_ci if (sigaction(SIGQUIT, &sa, NULL) == -1) 70762306a36Sopenharmony_ci shutdown(1, "sigaction(SIGQUIT)", __LINE__); 70862306a36Sopenharmony_ci if (sigaction(SIGTERM, &sa, NULL) == -1) 70962306a36Sopenharmony_ci shutdown(1, "sigaction(SIGTERM)", __LINE__); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (!continuous_mode_fake) { 71262306a36Sopenharmony_ci attr.mq_flags = O_NONBLOCK; 71362306a36Sopenharmony_ci attr.mq_maxmsg = cur_max_msgs; 71462306a36Sopenharmony_ci attr.mq_msgsize = MSG_SIZE; 71562306a36Sopenharmony_ci open_queue(&attr); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci for (i = 0; i < num_cpus_to_pin; i++) { 71862306a36Sopenharmony_ci pthread_attr_t thread_attr; 71962306a36Sopenharmony_ci void *thread_func; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (continuous_mode_fake) 72262306a36Sopenharmony_ci thread_func = &fake_cont_thread; 72362306a36Sopenharmony_ci else if (continuous_mode) 72462306a36Sopenharmony_ci thread_func = &cont_thread; 72562306a36Sopenharmony_ci else 72662306a36Sopenharmony_ci thread_func = &perf_test_thread; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci CPU_ZERO_S(cpu_set_size, cpu_set); 72962306a36Sopenharmony_ci CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set); 73062306a36Sopenharmony_ci pthread_attr_init(&thread_attr); 73162306a36Sopenharmony_ci pthread_attr_setaffinity_np(&thread_attr, cpu_set_size, 73262306a36Sopenharmony_ci cpu_set); 73362306a36Sopenharmony_ci if (pthread_create(&cpu_threads[i], &thread_attr, thread_func, 73462306a36Sopenharmony_ci NULL)) 73562306a36Sopenharmony_ci shutdown(1, "pthread_create()", __LINE__); 73662306a36Sopenharmony_ci pthread_attr_destroy(&thread_attr); 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (!continuous_mode) { 74062306a36Sopenharmony_ci pthread_join(cpu_threads[0], &retval); 74162306a36Sopenharmony_ci shutdown((long)retval, "perf_test_thread()", __LINE__); 74262306a36Sopenharmony_ci } else { 74362306a36Sopenharmony_ci while (1) 74462306a36Sopenharmony_ci sleep(1); 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci shutdown(0, "", 0); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cierr_code: 74962306a36Sopenharmony_ci CPU_FREE(cpu_set); 75062306a36Sopenharmony_ci exit(1); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci} 753