Home | History | Annotate | Download | only in eas
      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