/**************************************************************************** * apps/benchmarks/osperf/osperf.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /**************************************************************************** * Private Types ****************************************************************************/ struct performance_time_s { clock_t start; clock_t end; }; struct performance_thread_s { sem_t sem; struct performance_time_s time; }; struct performance_entry_s { const char name[NAME_MAX]; CODE size_t (*entry)(void); }; /**************************************************************************** * Private Functions Prototypes ****************************************************************************/ static size_t pthread_create_performance(void); static size_t pthread_switch_performance(void); static size_t context_switch_performance(void); static size_t hpwork_performance(void); static size_t poll_performance(void); static size_t semwait_performance(void); static size_t sempost_performance(void); /**************************************************************************** * Private Data ****************************************************************************/ static const struct performance_entry_s g_entry_list[] = { {"pthread-create", pthread_create_performance}, {"pthread-switch", pthread_switch_performance}, {"context-switch", context_switch_performance}, {"hpwork", hpwork_performance}, {"poll-write", poll_performance}, {"semwait", semwait_performance}, {"sempost", sempost_performance}, }; /**************************************************************************** * Private Functions ****************************************************************************/ static int performance_thread_create(FAR void *(*entry)(FAR void *), FAR void *arg, int priority) { struct sched_param param; pthread_attr_t attr; pthread_t tid; param.sched_priority = priority; pthread_attr_init(&attr); pthread_attr_setschedpolicy(&attr, SCHED_FIFO); pthread_attr_setschedparam(&attr, ¶m); pthread_create(&tid, &attr, entry, arg); DEBUGASSERT(tid > 0); return tid; } static void performance_start(FAR struct performance_time_s *result) { result->start = perf_gettime(); } static void performance_end(FAR struct performance_time_s *result) { result->end = perf_gettime(); } static size_t performance_gettime(FAR struct performance_time_s *result) { struct timespec ts; perf_convert(result->end - result->start, &ts); return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; } /**************************************************************************** * Pthread swtich performance ****************************************************************************/ static FAR void *pthread_switch_task(FAR void *arg) { FAR struct performance_thread_s *perf = arg; irq_t flags = enter_critical_section(); sem_wait(&perf->sem); performance_end(&perf->time); leave_critical_section(flags); return NULL; } static size_t pthread_switch_performance(void) { struct performance_thread_s perf; pthread_t tid; sem_init(&perf.sem, 0, 0); tid = performance_thread_create(pthread_switch_task, &perf, CONFIG_BENCHMARK_OSPERF_PRIORITY + 1); performance_start(&perf.time); sem_post(&perf.sem); pthread_join(tid, NULL); return performance_gettime(&perf.time); } /**************************************************************************** * Pthread create performance ****************************************************************************/ static FAR void *pthread_create_task(FAR void *arg) { FAR struct performance_time_s *time = arg; performance_end(time); return NULL; } static size_t pthread_create_performance(void) { struct performance_time_s result; struct sched_param param; pthread_attr_t attr; pthread_t tid; sched_getparam(gettid(), ¶m); param.sched_priority++; pthread_attr_init(&attr); pthread_attr_setschedpolicy(&attr, SCHED_FIFO); pthread_attr_setschedparam(&attr, ¶m); performance_start(&result); pthread_create(&tid, &attr, pthread_create_task, &result); pthread_join(tid, NULL); return performance_gettime(&result); } /**************************************************************************** * Contxt create performance ****************************************************************************/ static FAR void *context_swtich_task(FAR void *arg) { FAR struct performance_time_s *time = arg; sched_yield(); performance_end(time); return 0; } static size_t context_switch_performance(void) { struct performance_time_s time; int tid; tid = performance_thread_create(context_swtich_task, &time, CONFIG_INIT_PRIORITY); sched_yield(); performance_start(&time); sched_yield(); pthread_join(tid, NULL); return performance_gettime(&time); } /**************************************************************************** * wdog performance ****************************************************************************/ static void work_handle(void *arg) { FAR struct performance_time_s *time = ((FAR void **)arg)[2]; FAR sem_t *sem = ((void **)arg)[1]; performance_end(time); sem_post(sem); } static size_t hpwork_performance(void) { struct performance_time_s result; struct work_s work; sem_t sem = SEM_INITIALIZER(0); int ret; FAR void *args = (void *[]) { (FAR void *)&work, (FAR void *)&sem, (FAR void *)&result }; memset(&work, 0, sizeof(work)); performance_start(&result); ret = work_queue(HPWORK, &work, work_handle, args, 0); DEBUGASSERT(ret == 0); sem_wait(&sem); return performance_gettime(&result); } /**************************************************************************** * poll-write performance ****************************************************************************/ static FAR void *poll_task(FAR void *arg) { FAR void **argv = arg; FAR struct performance_time_s *time = argv[0]; int pipefd = (int)(uintptr_t)argv[1]; performance_start(time); write(pipefd, "a", 1); return 0; } static size_t poll_performance(void) { struct performance_time_s result; struct pollfd fds; FAR void *argv[2]; int pipefd[2]; int ret; ret = pipe(pipefd); DEBUGASSERT(ret == 0); fds.fd = pipefd[0]; fds.events = POLLIN; argv[0] = (FAR char *)&result; argv[1] = (FAR char *)(uintptr_t)pipefd[1]; ret = performance_thread_create(poll_task, argv, CONFIG_INIT_PRIORITY); poll(&fds, 1, -1); performance_end(&result); close(pipefd[0]); close(pipefd[1]); pthread_join(ret, NULL); return performance_gettime(&result); } /**************************************************************************** * semwait_performance ****************************************************************************/ static size_t semwait_performance(void) { struct performance_time_s result; sem_t sem; sem_init(&sem, 0, 2); performance_start(&result); sem_wait(&sem); performance_end(&result); sem_destroy(&sem); return performance_gettime(&result); } /**************************************************************************** * sempost_performance ****************************************************************************/ static size_t sempost_performance(void) { struct performance_time_s result; sem_t sem; sem_init(&sem, 0, 0); performance_start(&result); sem_post(&sem); performance_end(&result); sem_destroy(&sem); return performance_gettime(&result); } /**************************************************************************** * performance_help ****************************************************************************/ static void performance_help(void) { printf("Usage: performance [OPTIONS] [name]\n\n"); printf("OPTIONS:\n"); printf("\t-c, \tNumber of times to run each test\n"); printf("\t-d, \tShow detail of each test\n"); printf("\t-h, \tShow this help message\n"); printf("\t-l, \tList all tests\n"); } /**************************************************************************** * performance_run ****************************************************************************/ static void performance_run(const FAR struct performance_entry_s *item, size_t count, bool detail) { size_t total = 0; size_t max = 0; size_t min = 0; size_t i; for (i = 0; i < count; i++) { irq_t flags = enter_critical_section(); size_t time = item->entry(); leave_critical_section(flags); total += time; if (time > max) { max = time; } if (time < min || min == 0) { min = time; } if (detail) { printf("\t%zu: %zu\n", i, time); } } printf("%-*s %10zu %10zu %10zu\n", NAME_MAX, item->name, max, min, total / count); } /**************************************************************************** * Public Functions ****************************************************************************/ static const FAR struct performance_entry_s *find_entry(FAR const char *name) { size_t i; for (i = 0; i < nitems(g_entry_list); i++) { if (strcmp(name, g_entry_list[i].name) == 0) { return &g_entry_list[i]; } } return NULL; } void performance_list(void) { size_t i; for (i = 0; i < nitems(g_entry_list); i++) { printf("%s\n", g_entry_list[i].name); } } /**************************************************************************** * Public Functions ****************************************************************************/ int main(int argc, FAR char *argv[]) { const FAR struct performance_entry_s *item = NULL; bool detail = false; size_t count = 100; size_t i; int opt; while ((opt = getopt(argc, argv, "dc:hl")) != -1) { switch (opt) { case 'd': detail = true; break; case 'c': count = strtoul(optarg, NULL, 0); break; case 'h': performance_help(); return EXIT_SUCCESS; case 'l': performance_list(); return EXIT_SUCCESS; default: performance_help(); return EXIT_FAILURE; } } if (optind < argc) { item = find_entry(argv[optind]); if (item == NULL) { printf("Can't find %s\n", argv[optind]); return EXIT_FAILURE; } } printf("OS performance args: count:%zu, detail:%s\n", count, detail ? "true" : "false"); printf("==============================================================\n"); printf("%-*s %10s %10s %10s\n", NAME_MAX, "Describe", "Max", "Min", "Avg"); if (item != NULL) { performance_run(item, count, detail); return EXIT_SUCCESS; } for (i = 0; i < nitems(g_entry_list); i++) { item = &g_entry_list[i]; performance_run(item, count, detail); } return EXIT_SUCCESS; }