1 /*
2  * Copyright (c) 2019 Synopsys, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <stdio.h>
9 
10 /* Amount of execution threads to create and run */
11 #define THREADS_NUM	16
12 
13 /*
14  * Amount of digits of Pi to calculate, must be a multiple of 4,
15  * as used algorithm spits 4 digits on every iteration.
16  */
17 #define DIGITS_NUM	240
18 
19 #define LENGTH		((DIGITS_NUM / 4) * 14)
20 #define STACK_SIZE	((LENGTH * sizeof(int) + 1280))
21 
22 #ifdef CONFIG_SMP
23 #define CORES_NUM	arch_num_cpus()
24 #else
25 #define CORES_NUM	1
26 #endif
27 
28 static K_THREAD_STACK_ARRAY_DEFINE(tstack, THREADS_NUM, STACK_SIZE);
29 static struct k_thread tthread[THREADS_NUM];
30 static char th_buffer[THREADS_NUM][DIGITS_NUM + 1];
31 static atomic_t th_counter = THREADS_NUM;
32 
33 struct k_sem main_sem;
34 
test_thread(void * arg1,void * arg2,void * arg3)35 void test_thread(void *arg1, void *arg2, void *arg3)
36 {
37 	atomic_t *counter = (atomic_t *)arg1;
38 	char *buffer = (char *)arg2;
39 
40 	ARG_UNUSED(arg3);
41 
42 	/*
43 	 * Adapted and improved (for random number of digits) version of Pi
44 	 * calculation program initially proposed by Dik T. Winter as:
45 	 * -------------------------------->8--------------------------------
46 	 * int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b++]=a/5;
47 	 * for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)for(b=c;d+=f[b]*a,
48 	 * f[b]=d%--g,d/=g--,--b;d*=b);}
49 	 * -------------------------------->8--------------------------------
50 	 */
51 	#define NEW_BASE	10000
52 	#define ARRAY_INIT	2000
53 
54 	int array[LENGTH + 1] = {};
55 	int carry = 0;
56 	int i, j;
57 
58 	for (i = 0; i < LENGTH; i++) {
59 		array[i] = ARRAY_INIT;
60 	}
61 
62 	for (i = LENGTH; i > 0; i -= 14) {
63 		int sum = 0, value;
64 
65 		for (j = i; j > 0; --j) {
66 			sum = sum * j + NEW_BASE * array[j];
67 			array[j] = sum % (j * 2 - 1);
68 			sum /= j * 2 - 1;
69 		}
70 
71 		value = carry + sum / NEW_BASE;
72 		carry = sum % NEW_BASE;
73 
74 		/* Convert 4-digit int to string */
75 		sprintf(buffer, "%.4d", value);
76 		buffer += 4;
77 	}
78 
79 	if (atomic_dec(counter) == 1) {
80 		k_sem_give(&main_sem);
81 	}
82 }
83 
main(void)84 int main(void)
85 {
86 	uint32_t start_time, stop_time, cycles_spent, nanoseconds_spent;
87 	int i;
88 
89 	if (k_sem_init(&main_sem, 0, 1)) {
90 		printk("Failed initialization!\n");
91 		return -1;
92 	}
93 
94 	printk("Calculate first %d digits of Pi independently by %d threads.\n",
95 	       DIGITS_NUM, THREADS_NUM);
96 
97 	/* Capture initial time stamp */
98 	start_time = k_cycle_get_32();
99 
100 	for (i = 0; i < THREADS_NUM; i++) {
101 		k_thread_create(&tthread[i], tstack[i], STACK_SIZE,
102 			       test_thread,
103 			       (void *)&th_counter, (void *)th_buffer[i], NULL,
104 			       K_PRIO_COOP(10), 0, K_NO_WAIT);
105 	}
106 
107 	/* Wait for all workers to finish their calculations */
108 	k_sem_take(&main_sem, K_FOREVER);
109 
110 	/* Capture final time stamp */
111 	stop_time = k_cycle_get_32();
112 
113 	cycles_spent = stop_time - start_time;
114 	nanoseconds_spent = (uint32_t)k_cyc_to_ns_floor64(cycles_spent);
115 
116 	for (i = 0; i < THREADS_NUM; i++) {
117 		printk("Pi value calculated by thread #%d: %s\n", i, th_buffer[i]);
118 	}
119 
120 	printk("All %d threads executed by %d cores in %d msec\n", THREADS_NUM,
121 	       CORES_NUM, nanoseconds_spent / 1000 / 1000);
122 	return 0;
123 }
124