staticchar *usage = "Usage:\n" " %s [-c #[,#..] -f] path\n" "\n" " -c # Skip most tests and go straight to a high queue depth test\n" " and then run that test continuously (useful for running at\n" " the same time as some other workload to see how much the\n" " cache thrashing caused by adding messages to a very deep\n" " queue impacts the performance of other programs). The number\n" " indicates which CPU core we should bind the process to during\n" " the run. If you have more than one physical CPU, then you\n" " will need one copy per physical CPU package, and you should\n" " specify the CPU cores to pin ourself to via a comma separated\n" " list of CPU values.\n" " -f Only usable with continuous mode. Pin ourself to the CPUs\n" " as requested, then instead of looping doing a high mq\n" " workload, just busy loop. This will allow us to lock up a\n" " single CPU just like we normally would, but without actually\n" " thrashing the CPU cache. This is to make it easier to get\n" " comparable numbers from some other workload running on the\n" " other CPUs. One set of numbers with # CPUs locked up running\n" " an mq workload, and another set of numbers with those same\n" " CPUs locked away from the test workload, but not doing\n" " anything to trash the cache like the mq workload might.\n" " path Path name of the message queue to create\n" "\n" " Note: this program must be run as root in order to enable all tests\n" "\n";
#define MAX_CPUS 64 char *cpu_option_string; int cpus_to_pin[MAX_CPUS]; int num_cpus_to_pin;
pthread_t cpu_threads[MAX_CPUS];
pthread_t main_thread;
cpu_set_t *cpu_set; int cpu_set_size; int cpus_online;
#define MSG_SIZE 16 #define TEST1_LOOPS 10000000 #define TEST2_LOOPS 100000 int continuous_mode; int continuous_mode_fake;
struct rlimit saved_limits, cur_limits; int saved_max_msgs, saved_max_msgsize; int cur_max_msgs, cur_max_msgsize;
FILE *max_msgs, *max_msgsize; int cur_nice; char *queue_path = "/mq_perf_tests";
mqd_t queue = -1; struct mq_attr result; int mq_prio_max;
conststruct poptOption options[] = {
{
.longName = "continuous",
.shortName = 'c',
.argInfo = POPT_ARG_STRING,
.arg = &cpu_option_string,
.val = 'c',
.descrip = "Run continuous tests at a high queue depth in " "order to test the effects of cache thrashing on " "other tasks on the system. This test is intended " "to be run on one core of each physical CPU while " "some other CPU intensive task is run on all the other " "cores of that same physical CPU and the other task " "is timed. It is assumed that the process of adding " "messages to the message queue in a tight loop will " "impact that other task to some degree. Once the " "tests are performed in this way, you should then " "re-run the tests using fake mode in order to check " "the difference in time required to perform the CPU " "intensive task",
.argDescrip = "cpu[,cpu]",
},
{
.longName = "fake",
.shortName = 'f',
.argInfo = POPT_ARG_NONE,
.arg = &continuous_mode_fake,
.val = 0,
.descrip = "Tie up the CPUs that we would normally tie up in" "continuous mode, but don't actually do any mq stuff, " "just keep the CPU busy so it can't be used to process " "system level tasks as this would free up resources on " "the other CPU cores and skew the comparison between " "the no-mqueue work and mqueue work tests",
.argDescrip = NULL,
},
{
.longName = "path",
.shortName = 'p',
.argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
.arg = &queue_path,
.val = 'p',
.descrip = "The name of the path to use in the mqueue " "filesystem for our tests",
.argDescrip = "pathname",
},
POPT_AUTOHELP
POPT_TABLEEND
};
staticinlinevoid __set(FILE *stream, int value, char *err_msg)
{
rewind(stream); if (fprintf(stream, "%d", value) < 0)
perror(err_msg);
}
void shutdown(int exit_val, char *err_cause, int line_no)
{ staticint in_shutdown = 0; int errno_at_shutdown = errno; int i;
/* In case we get called by multiple threads or from an sighandler */ if (in_shutdown++) return;
/* Free the cpu_set allocated using CPU_ALLOC in main function */
CPU_FREE(cpu_set);
for (i = 0; i < num_cpus_to_pin; i++) if (cpu_threads[i]) {
pthread_kill(cpu_threads[i], SIGUSR1);
pthread_join(cpu_threads[i], NULL);
}
if (queue != -1) if (mq_close(queue))
perror("mq_close() during shutdown"); if (queue_path) /* *Besilentifthisfails,ifwecleanedupalreadyit's *expectedtofail
*/
mq_unlink(queue_path); if (saved_max_msgs)
__set(max_msgs, saved_max_msgs, "failed to restore saved_max_msgs"); if (saved_max_msgsize)
__set(max_msgsize, saved_max_msgsize, "failed to restore saved_max_msgsize"); if (exit_val)
error(exit_val, errno_at_shutdown, "%s at %d",
err_cause, line_no); exit(0);
}
void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context)
{ if (pthread_self() != main_thread)
pthread_exit(0); else {
fprintf(stderr, "Caught signal %d in SIGUSR1 handler, " "exiting\n", signum);
shutdown(0, "", 0);
fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n"); exit(0);
}
}
staticinlinevoid set(FILE *stream, int value)
{ int new_value;
rewind(stream); if (fprintf(stream, "%d", value) < 0) return shutdown(5, "Failed writing to /proc file", __LINE__);
new_value = get(stream); if (new_value != value) return shutdown(5, "We didn't get what we wrote to /proc back",
__LINE__);
}
staticinlineint try_set(FILE *stream, int value)
{ int new_value;
for (i = 0; i < num_cpus_to_pin; i++) if (cpu_threads[i] == pthread_self()) break;
printf("\tStarted fake continuous mode thread %d on CPU %d\n", i,
cpus_to_pin[i]); while (1)
;
}
void *cont_thread(void *arg)
{ char buff[MSG_SIZE]; int i; unsignedint priority;
for (i = 0; i < num_cpus_to_pin; i++) if (cpu_threads[i] == pthread_self()) break;
printf("\tStarted continuous mode thread %d on CPU %d\n", i,
cpus_to_pin[i]); while (1) { while (mq_send(queue, buff, sizeof(buff), 0) == 0)
;
mq_receive(queue, buff, sizeof(buff), &priority);
}
}
#define drain_queue() \ while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE)
#define do_untimed_send() \ do { \ if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
shutdown(3, "Test send failure", __LINE__); \
} while (0)
t = &cpu_threads[0];
printf("\n\tStarted mqueue performance test thread on CPU %d\n",
cpus_to_pin[0]);
mq_prio_max = sysconf(_SC_MQ_PRIO_MAX); if (mq_prio_max == -1)
shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__); if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0)
shutdown(2, "pthread_getcpuclockid", __LINE__);
if (clock_getres(clock, &res))
shutdown(2, "clock_getres()", __LINE__);
while ((rc = poptGetNextOpt(popt_context)) > 0) { switch (rc) { case'c':
continuous_mode = 1;
option = cpu_option_string; do {
next_option = strchr(option, ','); if (next_option)
*next_option = '\0';
cpu = atoi(option); if (cpu >= cpus_online)
fprintf(stderr, "CPU %d exceeds " "cpus online, ignoring.\n",
cpu); else
cpus_to_pin[num_cpus_to_pin++] = cpu; if (next_option)
option = ++next_option;
} while (next_option && num_cpus_to_pin < MAX_CPUS); /* Double check that they didn't give us the same CPU
* more than once */ for (cpu = 0; cpu < num_cpus_to_pin; cpu++) { if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size,
cpu_set)) {
fprintf(stderr, "Any given CPU may " "only be given once.\n"); goto err_code;
} else
CPU_SET_S(cpus_to_pin[cpu],
cpu_set_size, cpu_set);
} break; case'p': /* *Althoughwecancreateamsgqueuewitha *non-absolutepathname,unlinkwillfail.So, *ifthenamedoesn'tstartwitha/,addone *whenwesaveit.
*/
option = queue_path; if (*option != '/') {
queue_path = malloc(strlen(option) + 2); if (!queue_path) {
perror("malloc()"); goto err_code;
}
queue_path[0] = '/';
queue_path[1] = 0;
strcat(queue_path, option);
free(option);
} break;
}
}
if (continuous_mode && num_cpus_to_pin == 0) {
fprintf(stderr, "Must pass at least one CPU to continuous " "mode.\n");
poptPrintUsage(popt_context, stderr, 0); goto err_code;
} elseif (!continuous_mode) {
num_cpus_to_pin = 1;
cpus_to_pin[0] = cpus_online - 1;
}
max_msgs = fopen(MAX_MSGS, "r+");
max_msgsize = fopen(MAX_MSGSIZE, "r+"); if (!max_msgs)
shutdown(2, "Failed to open msg_max", __LINE__); if (!max_msgsize)
shutdown(2, "Failed to open msgsize_max", __LINE__);
/* Load up the current system values for everything we can */
getr(RLIMIT_MSGQUEUE, &saved_limits);
cur_limits = saved_limits;
saved_max_msgs = cur_max_msgs = get(max_msgs);
saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
errno = 0;
cur_nice = getpriority(PRIO_PROCESS, 0); if (errno)
shutdown(2, "getpriority()", __LINE__);
/* Tell the user our initial state */
printf("\nInitial system state:\n");
printf("\tUsing queue path:\t\t\t%s\n", queue_path);
printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
(long) saved_limits.rlim_cur);
printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
(long) saved_limits.rlim_max);
printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
printf("\tNice value:\t\t\t\t%d\n", cur_nice);
printf("\n");
increase_limits();
printf("Adjusted system state for testing:\n"); if (cur_limits.rlim_cur == RLIM_INFINITY) {
printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
} else {
printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
(long) cur_limits.rlim_cur);
printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
(long) cur_limits.rlim_max);
}
printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
printf("\tNice value:\t\t\t\t%d\n", cur_nice);
printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ?
(continuous_mode_fake ? "fake mode" : "enabled") : "disabled");
printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]); for (cpu = 1; cpu < num_cpus_to_pin; cpu++)
printf(",%d", cpus_to_pin[cpu]);
printf("\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.