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  * Two big and three small tasks execute. 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 task_tids[5];
     25 
     26 #define MAX_INCORRECT_CLUSTER_PCT 10
     27 #define BURN_SEC 3
     28 static void *task_fn(void *arg)
     29 {
     30 	int id = (int *)arg - task_tids;
     31 
     32 	task_tids[id] = gettid();
     33 
     34 	/* Tasks 0-2 are small, 3-4 are big. */
     35 	burn(BURN_SEC * USEC_PER_SEC, id < 3 ? 1 : 0);
     36 
     37 	return NULL;
     38 }
     39 
     40 static int parse_results(void)
     41 {
     42 	int i, j, pct, rv = 0;
     43 	unsigned long long exec_start_us[5] = { 0, 0, 0, 0, 0 };
     44 	unsigned long long incorrect_us[5] = { 0, 0, 0, 0, 0 };
     45 	unsigned long long total_us[5] = { 0, 0, 0, 0, 0 };
     46 	cpu_set_t cpuset;
     47 
     48 	if (find_cpus_with_capacity(0, &cpuset)) {
     49 		printf("Failed to find the CPUs in the little cluster.\n");
     50 		return -1;
     51 	}
     52 
     53 	for (i = 0; i < num_trace_records; i++) {
     54 		struct trace_sched_switch *t = trace[i].event_data;
     55 		unsigned long long segment_us;
     56 
     57 		if (trace[i].event_type != TRACE_RECORD_SCHED_SWITCH)
     58 			continue;
     59 
     60 		/* Is this the start of an execution segment? */
     61 		for (j = 0; j < 5; j++) {
     62 			if (t->next_pid != task_tids[j])
     63 				continue;
     64 			/* Start of execution segment for task j */
     65 			if (exec_start_us[j]) {
     66 				printf("Trace parse fail: double exec start\n");
     67 				return -1;
     68 			}
     69 			exec_start_us[j] = TS_TO_USEC(trace[i].ts);
     70 		}
     71 
     72 		/* Is this the end of an execution segment? */
     73 		for (j = 0; j < 5; j++) {
     74 			if (t->prev_pid != task_tids[j])
     75 				continue;
     76 			/* End of execution segment for task j */
     77 			segment_us = TS_TO_USEC(trace[i].ts);
     78 			segment_us -= exec_start_us[j];
     79 			exec_start_us[j] = 0;
     80 			if (CPU_ISSET(trace[i].cpu, &cpuset) && j > 2)
     81 				incorrect_us[j] += segment_us;
     82 			if (!CPU_ISSET(trace[i].cpu, &cpuset) && j < 3)
     83 				incorrect_us[j] += segment_us;
     84 			total_us[j] += segment_us;
     85 
     86 		}
     87 	}
     88 
     89 	for (i = 0; i < 3; i++) {
     90 		pct = (incorrect_us[i] * 100) / total_us[i];
     91 		rv |= (pct > MAX_INCORRECT_CLUSTER_PCT);
     92 		printf("Total time little task scheduled: %lld Time scheduled "
     93 		       "on big CPU: %lld (%d%%)\n", total_us[i],
     94 		       incorrect_us[i], pct);
     95 	}
     96 	for (i = 3; i < 5; i++) {
     97 		pct = (incorrect_us[i] * 100) / total_us[i];
     98 		rv |= (pct > MAX_INCORRECT_CLUSTER_PCT);
     99 		printf("Total time big task scheduled: %lld Time scheduled on "
    100 		       "little CPU: %lld (%d%%)\n", total_us[i],
    101 		       incorrect_us[i], pct);
    102 	}
    103 
    104 	return rv;
    105 }
    106 
    107 #define NUM_TASKS 5
    108 static void run(void)
    109 {
    110 	int i;
    111 	pthread_t tasks[NUM_TASKS];
    112 
    113 	tst_res(TINFO, "Maximum incorrect cluster time percentage: %d%%",
    114 		MAX_INCORRECT_CLUSTER_PCT);
    115 
    116 	printf("Tasks running for %d sec\n", BURN_SEC);
    117 
    118 	/* configure and enable tracing */
    119 	SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "0");
    120 	SAFE_FILE_PRINTF(TRACING_DIR "buffer_size_kb", "16384");
    121 	SAFE_FILE_PRINTF(TRACING_DIR "set_event", TRACE_EVENTS);
    122 	SAFE_FILE_PRINTF(TRACING_DIR "trace", "\n");
    123 	SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "1");
    124 
    125 	for (i = 0; i < NUM_TASKS; i++)
    126 		SAFE_PTHREAD_CREATE(&tasks[i], NULL, task_fn, &task_tids[i]);
    127 	for (i = 0; i < NUM_TASKS; i++)
    128 		SAFE_PTHREAD_JOIN(tasks[i], NULL);
    129 
    130 	/* disable tracing */
    131 	SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "0");
    132 	LOAD_TRACE();
    133 
    134 	if (parse_results())
    135 		tst_res(TFAIL, "Task placement goals were not met.\n");
    136 	else
    137 		tst_res(TPASS, "Task placement goals were met.\n");
    138 }
    139 
    140 static struct tst_test test = {
    141 	.test_all = run,
    142 	.cleanup = trace_cleanup,
    143 };
    144