1 /*
2 * Copyright (C) 2022 Intel Corporation.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 
7 #include "userApp.h"
8 
main(void)9 int main(void)
10 {
11 
12 	//First make sure the user is root
13 	if (geteuid() != 0) {
14 
15 		printf("You need to run this program as root!!!\n");
16 		return failure;
17 
18 	}
19 
20 	//Set up the interprocess communication system between userapp and webapp
21 	shm_addr = setup_ipcomms();
22 
23 	//Open the shared memory region
24 	string pci_fname = "/sys/class/uio/uio0/device/resource2";
25 	if (setup_ivshmem_region(pci_fname.c_str()) == failure) {
26 
27 		perror("Failed to open the shared memory region");
28 		return failure;
29 
30 	}
31 
32 	//Set up signal handler for when we get interrupt
33 	signal(SIGINT, sig_handler);
34 
35 	//Keep track of the latency data
36 	LatencyCounter latencies;
37 
38 	//Loop forever, reading the data and sending it to the UI
39 	while (1) {
40 
41 		//Process a data point
42 		if (process_data(latencies))
43 
44 			latencies.latenciesCount++;
45 
46 		//Dump the data if we have enough data points
47 		if ((latencies.latenciesCount > 0) && (latencies.latenciesCount % 100 == 0)) {
48 
49 			dump_data(latencies, shm_addr);
50 
51 			//Determine if we need to clear the Latency Counter
52 			if (latencies.latenciesCount >= 2000000)
53 
54 				latencies.clear();
55 
56 		}
57 
58 	}
59 
60 	//Close the shared memory region now that we don't need it
61 	close_ivshmem_region();
62 	remove_shm_region(shm_addr);
63 	shm_addr = NULL;
64 
65 	return success;
66 }
67 
68 /*
69 int process_data(LatencyCounter& latencies)
70 input: LatencyCounter& latencies - The class that holds the current latency data
71 output: int - 0 on success, -1 on failure
72 
73 This function processes a data point by reading the ivshmem region, parsing the data,
74 and incrementing the latency count in the latencies hash table
75 */
process_data(LatencyCounter & latencies)76 int process_data(LatencyCounter& latencies)
77 {
78 	//Clear the data
79 	bzero(data_buffer, BUFFERSIZE);
80 
81 	//Used to hold the latency value
82 	int actual_latency;
83 
84 	//Used to determine if the latency exists in the map
85 	int has_latency;
86 
87 	//Read the data from the RT vm
88 	if (read_ivshmem_region(data_buffer, BUFFERSIZE)) {
89 
90 		actual_latency = failure;
91 
92 		//Deteremine if we have a data point
93 		search_str = strstr(data_buffer, "Act:");
94 
95 		//Scan the data point if we have one
96 		if (search_str)
97 			sscanf(search_str, "Act: %d", &actual_latency);
98 
99 		//Update the latency count
100 		if (actual_latency != failure) {
101 
102 			//Determine if we have the latency value or create it if we do not
103 			has_latency = (*latencies.latencyValues).count(actual_latency);
104 			if (has_latency)
105 
106 				(*latencies.latencyValues)[actual_latency] = (*latencies.latencyValues)[actual_latency] + 1;
107 
108 
109 			else
110 
111 				(*latencies.latencyValues)[actual_latency] = 1;
112 
113 			return 1;
114 
115 		}
116 
117 	}
118 
119 	return success;
120 
121 }
122 /*
123 char *setup_ipcomms(void)
124 output: char * - A pointer to the shared memory region or NULL on failure
125 
126 This function sets up the shared memory and synchronization between the userapp and the webapp
127 */
setup_ipcomms(void)128 char *setup_ipcomms(void)
129 {
130 
131 	//Set up the shm region
132 	char *shm_region = setup_shm_region();
133 	if (!shm_region)
134 
135 		return shm_region;
136 
137 	//Set up the semaphore for synchronization with initial value of 1
138 	web_sem  = sem_open(SEM_KEY, O_CREAT | O_RDWR | O_SYNC, 0666, 1);
139 	if (web_sem == SEM_FAILED) {
140 
141 		perror("Failed to create the semaphore");
142 		remove_shm_region(shm_region);
143 		shm_region = NULL;
144 
145 	}
146 
147 	return shm_region;
148 
149 }
150 
151 /*
152 char *setup_shm_region(void)
153 output: char * - A pointer to the shared memory region or NULL on failure
154 
155 This function sets up a shared memory region to be used between the userapp and the
156 webapp
157 */
setup_shm_region(void)158 char *setup_shm_region(void)
159 {
160 	void *shared_mem_region = NULL;
161 
162 	//ID for the memory region
163 	int shm_id;
164 
165 	shm_unlink(SHM_KEY);
166 
167 	//Set up the shared memory region
168 	shm_id = shm_open(SHM_KEY, O_CREAT | O_RDWR, 0);
169 	if (shm_id == failure) {
170 
171 		perror("Failed to get the shared memory region");
172 		return (char *)shared_mem_region;
173 
174 	}
175 
176 	//Set the size of the shared memory region so we avoid bus error
177 	ftruncate(shm_id, SHM_SIZE);
178 
179 	//Map the shared memory region
180 	shared_mem_region = mmap(0, SHM_SIZE, O_RDWR, MAP_SHARED, shm_id, 0);
181 	if (shared_mem_region == (void *)failure) {
182 
183 		perror("SHMAT ERROR");
184 		shmctl(shm_id, IPC_RMID, NULL);
185 		shared_mem_region = NULL;
186 		return (char *)shared_mem_region;
187 
188 	}
189 
190 	return (char *)shared_mem_region;
191 
192 }
193 
194 /*
195 void remove_shm_region(void)
196 output: int - 0 on success, -1 on failure
197 
198 This function tears down the shared memory region
199 */
remove_shm_region(void * shm_region)200 int remove_shm_region(void *shm_region)
201 {
202 
203 	//Detach the shared memory region from the process
204 	return shmdt(shm_region);
205 
206 }
207 
208 /*
209 int dump_data(LatencyCounter& latencies, char *region)
210 input: LatencyCounter& latencies - The class that holds the current latency data
211 input: char *region - The region to copy the data to.
212 output: int - 0 on success, -1 on failure
213 
214 This function will dump the latency counts and values to the shared memory region
215 that the python web server will use
216 */
dump_data(LatencyCounter & latencies,char * region)217 int dump_data(LatencyCounter& latencies, char *region)
218 {
219 
220 	//Get the shared memory region
221 	char *current_place = region;
222 	if (current_place == (char *)NULL) {
223 
224 		printf("Shared memory region is not setup\n");
225 		return failure;
226 
227 	}
228 
229 	//Holds the total count of the latencies so we can send percentages over
230 	unsigned int total_count = latencies.latenciesCount;
231 
232 	//Latency value percentage
233 	int percentage;
234 
235 	//First lock the semaphore so we can write
236 	sem_wait(web_sem);
237 
238 	//Dump the current count of the values before the percentages
239 	current_place += sprintf(current_place, "%u ", latencies.latenciesCount);
240 
241 	//Iterate over each value in the latencies map, placing the value in the shared memory region
242 	for(unordered_map<int,int>::iterator i = (*latencies.latencyValues).begin(); i != (*latencies.latencyValues).end(); i++) {
243 
244 		percentage = (i->second * 100 / total_count);
245 
246 		//Only copy the latency value if it is at least 1 percentage point to filter out outliers
247 		if (percentage > 0)
248 
249 			current_place += sprintf(current_place, "%d %d ", i->first, percentage);
250 
251 	}
252 
253 	sprintf(current_place, "\n");
254 
255 	sem_post(web_sem);
256 
257 	return success;
258 
259 }
260 
261 /*
262 void sig_handler(int signum)
263 input: int - the signal value
264 
265 This function will get run when a signal is sent to the process and will gracefully
266 shut down the program
267 */
sig_handler(int signum)268 void sig_handler(int signum)
269 {
270 
271 	fprintf(stderr, "Received signal: %d\n", signum);
272 
273 	//Close the shared memory region now that we don't need it
274 	close_ivshmem_region();
275 	remove_shm_region(shm_addr);
276 	shm_addr = NULL;
277 
278 	exit(-1);
279 
280 }
281