1 /* 2 * Copyright (c) 2018 Google, Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0-or-later 5 * 6 * A single small task executes. Task placement is verified. 7 */ 8 9 #define _GNU_SOURCE 10 #include <errno.h> 11 #include <pthread.h> 12 #include <sched.h> 13 #include <time.h> 14 15 #include "tst_test.h" 16 #include "tst_safe_file_ops.h" 17 #include "tst_safe_pthread.h" 18 19 #include "trace_parse.h" 20 #include "util.h" 21 22 #define TRACE_EVENTS "sched_switch" 23 24 static int small_task_tid; 25 26 #define MIN_CORRECT_CLUSTER_PCT 90 27 #define BURN_SEC 5 28 static void *task_fn(void *arg LTP_ATTRIBUTE_UNUSED) 29 { 30 small_task_tid = gettid(); 31 32 printf("Small task executing for %ds...\n", BURN_SEC); 33 burn(BURN_SEC * USEC_PER_SEC, 1); 34 35 return NULL; 36 } 37 38 static int parse_results(void) 39 { 40 int i, pct; 41 unsigned long long exec_start_us = 0; 42 unsigned long long correct_us = 0; 43 unsigned long long total_us = 0; 44 cpu_set_t cpuset; 45 46 if (find_cpus_with_capacity(0, &cpuset)) { 47 printf("Failed to find the CPUs in the little cluster.\n"); 48 return -1; 49 } 50 51 for (i = 0; i < num_trace_records; i++) { 52 struct trace_sched_switch *t = trace[i].event_data; 53 unsigned long long segment_us; 54 55 if (trace[i].event_type != TRACE_RECORD_SCHED_SWITCH) 56 continue; 57 58 if (t->next_pid == small_task_tid) { 59 if (exec_start_us) { 60 printf("Trace parse fail: double exec start\n"); 61 return -1; 62 } 63 exec_start_us = TS_TO_USEC(trace[i].ts); 64 continue; 65 } 66 if (t->prev_pid != small_task_tid) 67 continue; 68 /* End of task execution segment. */ 69 if (!exec_start_us) { 70 printf("Trace parse fail: double exec end\n"); 71 return -1; 72 } 73 segment_us = TS_TO_USEC(trace[i].ts); 74 segment_us -= exec_start_us; 75 exec_start_us = 0; 76 if (CPU_ISSET(trace[i].cpu, &cpuset)) 77 correct_us += segment_us; 78 total_us += segment_us; 79 } 80 81 pct = (correct_us * 100) / total_us; 82 printf("Total time task scheduled: %lld usec\n" 83 "Time scheduled on a little CPU: %lld usec (%d%%)\n", 84 total_us, correct_us, pct); 85 86 return (pct < MIN_CORRECT_CLUSTER_PCT); 87 } 88 89 static void run(void) 90 { 91 pthread_t task_thread; 92 93 tst_res(TINFO, "Minimum correct cluster time percentage: %d%%\n", 94 MIN_CORRECT_CLUSTER_PCT); 95 96 /* configure and enable tracing */ 97 SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "0"); 98 SAFE_FILE_PRINTF(TRACING_DIR "buffer_size_kb", "16384"); 99 SAFE_FILE_PRINTF(TRACING_DIR "set_event", TRACE_EVENTS); 100 SAFE_FILE_PRINTF(TRACING_DIR "trace", "\n"); 101 SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "1"); 102 103 SAFE_PTHREAD_CREATE(&task_thread, NULL, task_fn, NULL); 104 SAFE_PTHREAD_JOIN(task_thread, NULL); 105 106 /* disable tracing */ 107 SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "0"); 108 LOAD_TRACE(); 109 110 if (parse_results()) 111 tst_res(TFAIL, "Small task ran too much on non-small CPUs.\n"); 112 else 113 tst_res(TPASS, "Small task ran appropriately on small CPUs.\n"); 114 } 115 116 static struct tst_test test = { 117 .test_all = run, 118 .cleanup = trace_cleanup, 119 }; 120