mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-24 14:33:38 +00:00
sample app: initial import of the sample app
This sample application allows the user to get the hypervisor and a simple Virtual Machine Scenario to run This sample application assumes the user is following the sample app guide in the acrn hypervisor documentation Tracked-On: #7820 Signed-off-by: Matthew Leon <matthew.leon@intel.com>
This commit is contained in:
parent
c6fcda2a0d
commit
d8f55c7bca
7
misc/sample_application/README.md
Normal file
7
misc/sample_application/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
This directory contains the software that is necessary to run a real-time application between a real-time VM and a standard VM using the acrn-hypervisor.
|
||||
|
||||
The rtvm directory contains the code required to pipe data from cyclictest to the uservm using the inter-vm shared memory feature that acrn-hypervisor exposes to its VMs.
|
||||
|
||||
The uservm directory contains the code required to read the piped data from the rtvm, process the data, and display that data over a web application that can be accessed from the hypervisor's service VM.
|
||||
|
||||
To build and run the applications, copy this repo to your VMs, run make in the directory that corresponds to the VM that you are running, and then follow the sample app guide in the acrn-hypervisor documentation.
|
12
misc/sample_application/rtvm/Makefile
Normal file
12
misc/sample_application/rtvm/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
CC = gcc
|
||||
CP = g++
|
||||
|
||||
CFLAGS = -Wall -Wextra -Wabi=11 -pedantic
|
||||
|
||||
LDLIBS = -lrt -pthread
|
||||
|
||||
all: rtApp.c
|
||||
$(CC) $(CFLAGS) -o rtapp rtApp.c ivshmemlib.c
|
||||
|
||||
clean:
|
||||
rm rtapp
|
148
misc/sample_application/rtvm/ivshmemlib.c
Normal file
148
misc/sample_application/rtvm/ivshmemlib.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "ivshmemlib.h"
|
||||
|
||||
//The shared memory region that is used for inter-vm shared memory
|
||||
char *ivshmem_ptr = NULL;
|
||||
|
||||
/*
|
||||
int setup_ivshmem_region(const char *f_path)
|
||||
input: char *f_path - A string containing the pci resource2 filepath
|
||||
output: int - Whether the setup succeeded or not
|
||||
|
||||
This function attempts to open the file whose path is f_path
|
||||
On success it returns 0
|
||||
On failure it returns -1
|
||||
*/
|
||||
int setup_ivshmem_region(const char *f_path)
|
||||
{
|
||||
|
||||
//Open the file so we can map it into memory
|
||||
int pci_file = open(f_path, O_RDWR | O_SYNC);
|
||||
if (pci_file == failure) {
|
||||
|
||||
perror("Failed to open the resource2 file\n");
|
||||
return failure;
|
||||
|
||||
}
|
||||
|
||||
//Map the file into memory
|
||||
ivshmem_ptr = (char *)mmap(0, REGION_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, pci_file , 0);
|
||||
close(pci_file);
|
||||
if (!ivshmem_ptr) {
|
||||
|
||||
perror("Failed to map the shared memory region into our address space\n");
|
||||
return failure;
|
||||
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
int close_ivshmem_region(void)
|
||||
output: int - Whether unmapping the region succeeded or not.
|
||||
|
||||
This function closes the ivshmem region
|
||||
On success it returns 0
|
||||
On failure it returns -1
|
||||
*/
|
||||
int close_ivshmem_region(void)
|
||||
{
|
||||
|
||||
int ret_val = failure;
|
||||
|
||||
//Determine if ivshmem region is set up
|
||||
if (ivshmem_ptr) {
|
||||
|
||||
ret_val = munmap(ivshmem_ptr, REGION_SIZE);
|
||||
ivshmem_ptr = NULL;
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
printf("Ivshmem region is not set up.");
|
||||
|
||||
return ret_val;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
size_t read_ivshmem_region(char *ivshmemPtr, char *user_ptr, size_t size)
|
||||
input: char *user_ptr - The memory to write to
|
||||
input: size_t size - the number of bytes to read from the memory
|
||||
output: size_t - The number of bytes that were successfully read or -1 on failure
|
||||
|
||||
This function reads from the ivshmem region and copies size - 1 bytes
|
||||
from the shared memory region to the user_ptr
|
||||
and null-terminates the string
|
||||
*/
|
||||
size_t read_ivshmem_region(char *user_ptr, size_t size)
|
||||
{
|
||||
//Number of bytes copied
|
||||
size_t ret = failure;
|
||||
|
||||
//Make sure that we actually need to read something
|
||||
if (size == 0)
|
||||
return ret;
|
||||
|
||||
//Determine if ivshmem region is set up
|
||||
if (ivshmem_ptr) {
|
||||
|
||||
//Do the copy and zero out the ivshmem region
|
||||
strncpy(user_ptr, ivshmem_ptr, size - 1);
|
||||
user_ptr[size] = 0;
|
||||
ret = strlen(user_ptr);
|
||||
bzero(ivshmem_ptr, ret);
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
printf("Ivshmem region is not set up.");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
size_t write_ivshmem_region(char *ivshmemPtr, char *user_ptr, size_t size)
|
||||
input: char *user_ptr - The memory to read from
|
||||
input: int size - the number of bytes to write from the memory
|
||||
output: int - The number of bytes that were successfully written or -1 on failure
|
||||
|
||||
This function reads from the user_ptr and copies size - 1 bytes
|
||||
to the shared memory region
|
||||
and null-terminates the string
|
||||
*/
|
||||
size_t write_ivshmem_region(char *user_ptr, size_t size)
|
||||
{
|
||||
//Return value that holds the amount of bytes that were copied from the user_ptr
|
||||
size_t ret = failure;
|
||||
|
||||
//Make sure that we need to actually write something
|
||||
if (size == 0)
|
||||
|
||||
return ret;
|
||||
|
||||
//Determine if ivshmem region is set up
|
||||
if (ivshmem_ptr) {
|
||||
|
||||
//Do the copy and zero out the user_ptr
|
||||
strncpy(ivshmem_ptr, user_ptr, size - 1);
|
||||
user_ptr[size] = 0;
|
||||
ret = strlen(ivshmem_ptr);
|
||||
bzero(user_ptr, ret);
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
printf("Ivshmem region is not set up.");
|
||||
|
||||
return ret;
|
||||
}
|
23
misc/sample_application/rtvm/ivshmemlib.h
Normal file
23
misc/sample_application/rtvm/ivshmemlib.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
//The size of the shared memory region
|
||||
#define REGION_SIZE 32768
|
||||
|
||||
enum return_vals {success = 0, failure = -1};
|
||||
|
||||
int setup_ivshmem_region(const char*);
|
||||
int close_ivshmem_region(void);
|
||||
size_t read_ivshmem_region(char *, size_t);
|
||||
size_t write_ivshmem_region(char *, size_t);
|
104
misc/sample_application/rtvm/rtApp.c
Normal file
104
misc/sample_application/rtvm/rtApp.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "ivshmemlib.h"
|
||||
|
||||
#define BUFFERSIZE 256
|
||||
|
||||
//Used for reading output from cyclictest
|
||||
int data_pipe = -1;
|
||||
|
||||
//Used for handling signals
|
||||
void sig_handler(int);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
//First make sure the user is root
|
||||
if (geteuid() != 0) {
|
||||
|
||||
printf("You need to run this program as root!!!\n");
|
||||
return failure;
|
||||
|
||||
}
|
||||
|
||||
//Used for holding the data from cyclictest
|
||||
char data_buffer[BUFFERSIZE] = {0};
|
||||
|
||||
//Used for sanitizing the data
|
||||
char *start_stat = NULL;
|
||||
|
||||
//Set up signal handler for when we get interrupt
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
//Used for reading output from cyclictest
|
||||
data_pipe = open("data_pipe", O_RDWR);
|
||||
if (data_pipe == failure) {
|
||||
|
||||
perror("Failed to open a fifo pipe");
|
||||
return failure;
|
||||
|
||||
}
|
||||
|
||||
//Open the shared memory region
|
||||
if (setup_ivshmem_region("/sys/class/uio/uio0/device/resource2") == failure) {
|
||||
|
||||
perror("Failed to open the shared memory region");
|
||||
close(data_pipe);
|
||||
return failure;
|
||||
|
||||
}
|
||||
|
||||
//Loop forever, reading and writing the data from cyclictest to the uservm
|
||||
while (1) {
|
||||
|
||||
//Read the data
|
||||
bzero(data_buffer, BUFFERSIZE);
|
||||
read(data_pipe, data_buffer, BUFFERSIZE);
|
||||
|
||||
//Get the sample stat
|
||||
start_stat = strstr(data_buffer, "T:");
|
||||
if (start_stat != NULL)
|
||||
|
||||
//Send the data
|
||||
write_ivshmem_region(start_stat, BUFFERSIZE);
|
||||
|
||||
}
|
||||
|
||||
//Close the shared memory region and the data pipe now that we don't need them
|
||||
close_ivshmem_region();
|
||||
close(data_pipe);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
void sig_handler(int signum)
|
||||
input: int - the signal value
|
||||
|
||||
This function will get run when a signal is sent to the process and will gracefully
|
||||
shut down the program
|
||||
*/
|
||||
void sig_handler(int signum)
|
||||
{
|
||||
|
||||
fprintf(stderr, "Received signal: %d\n", signum);
|
||||
|
||||
//Close the shared memory region and the data pipe now that we don't need them
|
||||
close_ivshmem_region();
|
||||
if (data_pipe != -1)
|
||||
close(data_pipe);
|
||||
|
||||
exit(-1);
|
||||
|
||||
}
|
12
misc/sample_application/uservm/Makefile
Normal file
12
misc/sample_application/uservm/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
CC = gcc
|
||||
CP = g++
|
||||
|
||||
CFLAGS = -Wall -Wextra -Wabi=11 -pedantic
|
||||
|
||||
LDLIBS = -lrt -pthread
|
||||
|
||||
all: userApp.cpp
|
||||
$(CP) $(CFLAGS) -o userapp userApp.cpp ivshmemlib.c $(LDLIBS)
|
||||
|
||||
clean:
|
||||
rm userapp
|
93
misc/sample_application/uservm/histapp.py
Normal file
93
misc/sample_application/uservm/histapp.py
Normal file
@ -0,0 +1,93 @@
|
||||
"""
|
||||
* Copyright (C) 2022 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
"""
|
||||
|
||||
from flask import Flask
|
||||
from flask import send_file
|
||||
|
||||
import numpy as np
|
||||
import pandas
|
||||
import random
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
import posix_ipc as ipc
|
||||
import mmap
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
#Runs when the user goes to our ip address
|
||||
@app.route('/')
|
||||
def histapp():
|
||||
|
||||
#Create and save the figure
|
||||
create_hist()
|
||||
|
||||
#Send the histogram as a webpage to the user
|
||||
return send_file("hist.png", mimetype='image/png')
|
||||
|
||||
#Creates the user histogram and saves to hist.png
|
||||
def create_hist():
|
||||
|
||||
#Go to the beginning of the shared memory region
|
||||
shm.seek(0)
|
||||
|
||||
#Get the data
|
||||
web_sem.acquire()
|
||||
data = shm.readline();
|
||||
web_sem.release()
|
||||
|
||||
#Transform the data into an array that matplotlib can understand
|
||||
dataset = transform_data(data)
|
||||
|
||||
#Clear the figure and recreate from the new data
|
||||
plt.clf()
|
||||
|
||||
#Setup the figure and save it
|
||||
figure = plt.hist(dataset)
|
||||
|
||||
#plt.title("Latencies where count = " + str(total_count))
|
||||
plt.title("Latencies percentages")
|
||||
plt.xlabel("Latency Value (ms)")
|
||||
plt.ylabel("Frequency")
|
||||
plt.savefig("hist.png")
|
||||
|
||||
return figure
|
||||
|
||||
def transform_data(data_string):
|
||||
transformed_data_values = []
|
||||
|
||||
str_data = data_string.decode("utf-8")
|
||||
str_data = str_data.replace('\n',"")
|
||||
|
||||
data_values = str_data.split()
|
||||
|
||||
#Holds the count of latencies that we have
|
||||
total_count = data_values[0]
|
||||
|
||||
#Used for transforming the data values
|
||||
data_percentages = data_values[1:]
|
||||
if (len(data_percentages) % 2 != 0):
|
||||
return transformed_data_values
|
||||
|
||||
#Transform the data into a list that can be fed to matplotlib
|
||||
for i in range(0, int(len(data_percentages) / 2)):
|
||||
transformed_data_values += ([data_values[i*2]] * data_values[i*2 + 1])
|
||||
|
||||
return transformed_data_values
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
#Set up shared memory between userapp and the webserver
|
||||
shm_path = "/pyservershm"
|
||||
shm_size = 1048576
|
||||
shm_f = ipc.SharedMemory(shm_path, 0, size=shm_size)
|
||||
shm = mmap.mmap(shm_f.fd, shm_size)
|
||||
|
||||
#Set up the semaphore to maintaine synchronization
|
||||
web_sem = ipc.Semaphore("/pyserversem", 0, 0o0774)
|
||||
|
||||
#Run the webserver
|
||||
app.run(host="0.0.0.0", port=80, debug=True)
|
148
misc/sample_application/uservm/ivshmemlib.c
Normal file
148
misc/sample_application/uservm/ivshmemlib.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "ivshmemlib.h"
|
||||
|
||||
//The shared memory region that is used for inter-vm shared memory
|
||||
char *ivshmem_ptr = NULL;
|
||||
|
||||
/*
|
||||
int setup_ivshmem_region(const char *f_path)
|
||||
input: char *f_path - A string containing the pci resource2 filepath
|
||||
output: int - Whether the setup succeeded or not
|
||||
|
||||
This function attempts to open the file whose path is f_path
|
||||
On success it returns 0
|
||||
On failure it returns -1
|
||||
*/
|
||||
int setup_ivshmem_region(const char *f_path)
|
||||
{
|
||||
|
||||
//Open the file so we can map it into memory
|
||||
int pci_file = open(f_path, O_RDWR | O_SYNC);
|
||||
if (pci_file == failure) {
|
||||
|
||||
perror("Failed to open the resource2 file\n");
|
||||
return failure;
|
||||
|
||||
}
|
||||
|
||||
//Map the file into memory
|
||||
ivshmem_ptr = (char *)mmap(0, REGION_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, pci_file , 0);
|
||||
close(pci_file);
|
||||
if (!ivshmem_ptr) {
|
||||
|
||||
perror("Failed to map the shared memory region into our address space\n");
|
||||
return failure;
|
||||
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
int close_ivshmem_region(void)
|
||||
output: int - Whether unmapping the region succeeded or not.
|
||||
|
||||
This function closes the ivshmem region
|
||||
On success it returns 0
|
||||
On failure it returns -1
|
||||
*/
|
||||
int close_ivshmem_region(void)
|
||||
{
|
||||
|
||||
int ret_val = failure;
|
||||
|
||||
//Determine if ivshmem region is set up
|
||||
if (ivshmem_ptr) {
|
||||
|
||||
ret_val = munmap(ivshmem_ptr, REGION_SIZE);
|
||||
ivshmem_ptr = NULL;
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
printf("Ivshmem region is not set up.");
|
||||
|
||||
return ret_val;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
size_t read_ivshmem_region(char *ivshmemPtr, char *user_ptr, size_t size)
|
||||
input: char *user_ptr - The memory to write to
|
||||
input: size_t size - the number of bytes to read from the memory
|
||||
output: size_t - The number of bytes that were successfully read or -1 on failure
|
||||
|
||||
This function reads from the ivshmem region and copies size - 1 bytes
|
||||
from the shared memory region to the user_ptr
|
||||
and null-terminates the string
|
||||
*/
|
||||
size_t read_ivshmem_region(char *user_ptr, size_t size)
|
||||
{
|
||||
//Number of bytes copied
|
||||
size_t ret = failure;
|
||||
|
||||
//Make sure that we actually need to read something
|
||||
if (size == 0)
|
||||
return ret;
|
||||
|
||||
//Determine if ivshmem region is set up
|
||||
if (ivshmem_ptr) {
|
||||
|
||||
//Do the copy and zero out the ivshmem region
|
||||
strncpy(user_ptr, ivshmem_ptr, size - 1);
|
||||
user_ptr[size] = 0;
|
||||
ret = strlen(user_ptr);
|
||||
bzero(ivshmem_ptr, ret);
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
printf("Ivshmem region is not set up.");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
size_t write_ivshmem_region(char *ivshmemPtr, char *user_ptr, size_t size)
|
||||
input: char *user_ptr - The memory to read from
|
||||
input: int size - the number of bytes to write from the memory
|
||||
output: int - The number of bytes that were successfully written or -1 on failure
|
||||
|
||||
This function reads from the user_ptr and copies size - 1 bytes
|
||||
to the shared memory region
|
||||
and null-terminates the string
|
||||
*/
|
||||
size_t write_ivshmem_region(char *user_ptr, size_t size)
|
||||
{
|
||||
//Return value that holds the amount of bytes that were copied from the user_ptr
|
||||
size_t ret = failure;
|
||||
|
||||
//Make sure that we need to actually write something
|
||||
if (size == 0)
|
||||
|
||||
return ret;
|
||||
|
||||
//Determine if ivshmem region is set up
|
||||
if (ivshmem_ptr) {
|
||||
|
||||
//Do the copy and zero out the user_ptr
|
||||
strncpy(ivshmem_ptr, user_ptr, size - 1);
|
||||
user_ptr[size] = 0;
|
||||
ret = strlen(ivshmem_ptr);
|
||||
bzero(user_ptr, ret);
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
printf("Ivshmem region is not set up.");
|
||||
|
||||
return ret;
|
||||
}
|
23
misc/sample_application/uservm/ivshmemlib.h
Normal file
23
misc/sample_application/uservm/ivshmemlib.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
//The size of the shared memory region
|
||||
#define REGION_SIZE 32768
|
||||
|
||||
enum return_vals {success = 0, failure = -1};
|
||||
|
||||
int setup_ivshmem_region(const char*);
|
||||
int close_ivshmem_region(void);
|
||||
size_t read_ivshmem_region(char *, size_t);
|
||||
size_t write_ivshmem_region(char *, size_t);
|
280
misc/sample_application/uservm/userApp.cpp
Normal file
280
misc/sample_application/uservm/userApp.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "userApp.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
//First make sure the user is root
|
||||
if (geteuid() != 0) {
|
||||
|
||||
printf("You need to run this program as root!!!\n");
|
||||
return failure;
|
||||
|
||||
}
|
||||
|
||||
//Set up the interprocess communication system between userapp and webapp
|
||||
shm_addr = setup_ipcomms();
|
||||
|
||||
//Open the shared memory region
|
||||
string pci_fname = "/sys/class/uio/uio0/device/resource2";
|
||||
if (setup_ivshmem_region(pci_fname.c_str()) == failure) {
|
||||
|
||||
perror("Failed to open the shared memory region");
|
||||
return failure;
|
||||
|
||||
}
|
||||
|
||||
//Set up signal handler for when we get interrupt
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
//Keep track of the latency data
|
||||
LatencyCounter latencies;
|
||||
|
||||
//Loop forever, reading the data and sending it to the UI
|
||||
while (1) {
|
||||
|
||||
//Process a data point
|
||||
if (process_data(latencies))
|
||||
|
||||
latencies.latenciesCount++;
|
||||
|
||||
//Dump the data if we have enough data points
|
||||
if (latencies.latenciesCount % 100 == 0) {
|
||||
|
||||
dump_data(latencies, shm_addr);
|
||||
|
||||
//Determine if we need to clear the Latency Counter
|
||||
if (latencies.latenciesCount >= 2000000)
|
||||
|
||||
latencies.clear();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Close the shared memory region now that we don't need it
|
||||
close_ivshmem_region();
|
||||
remove_shm_region(shm_addr);
|
||||
shm_addr = NULL;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
int process_data(LatencyCounter& latencies)
|
||||
input: LatencyCounter& latencies - The class that holds the current latency data
|
||||
output: int - 0 on success, -1 on failure
|
||||
|
||||
This function processes a data point by reading the ivshmem region, parsing the data,
|
||||
and incrementing the latency count in the latencies hash table
|
||||
*/
|
||||
int process_data(LatencyCounter& latencies)
|
||||
{
|
||||
//Clear the data
|
||||
bzero(data_buffer, BUFFERSIZE);
|
||||
|
||||
//Used to hold the latency value
|
||||
int actual_latency;
|
||||
|
||||
//Used to determine if the latency exists in the map
|
||||
int has_latency;
|
||||
|
||||
//Read the data from the RT vm
|
||||
if (read_ivshmem_region(data_buffer, BUFFERSIZE)) {
|
||||
|
||||
actual_latency = failure;
|
||||
|
||||
//Deteremine if we have a data point
|
||||
search_str = strstr(data_buffer, "Act:");
|
||||
|
||||
//Scan the data point if we have one
|
||||
if (search_str)
|
||||
sscanf(search_str, "Act: %d", &actual_latency);
|
||||
|
||||
//Update the latency count
|
||||
if (actual_latency != failure) {
|
||||
|
||||
//Determine if we have the latency value or create it if we do not
|
||||
has_latency = (*latencies.latencyValues).count(actual_latency);
|
||||
if (has_latency)
|
||||
|
||||
(*latencies.latencyValues)[actual_latency] = (*latencies.latencyValues)[actual_latency] + 1;
|
||||
|
||||
|
||||
else
|
||||
|
||||
(*latencies.latencyValues)[actual_latency] = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return success;
|
||||
|
||||
}
|
||||
/*
|
||||
char *setup_ipcomms(void)
|
||||
output: char * - A pointer to the shared memory region or NULL on failure
|
||||
|
||||
This function sets up the shared memory and synchronization between the userapp and the webapp
|
||||
*/
|
||||
char *setup_ipcomms(void)
|
||||
{
|
||||
|
||||
//Set up the shm region
|
||||
char *shm_region = setup_shm_region();
|
||||
if (!shm_region)
|
||||
|
||||
return shm_region;
|
||||
|
||||
//Set up the semaphore for synchronization with initial value of 1
|
||||
web_sem = sem_open(SEM_KEY, O_CREAT | O_RDWR | O_SYNC, 0666, 1);
|
||||
if (web_sem == SEM_FAILED) {
|
||||
|
||||
perror("Failed to create the semaphore");
|
||||
remove_shm_region(shm_region);
|
||||
shm_region = NULL;
|
||||
|
||||
}
|
||||
|
||||
return shm_region;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
char *setup_shm_region(void)
|
||||
output: char * - A pointer to the shared memory region or NULL on failure
|
||||
|
||||
This function sets up a shared memory region to be used between the userapp and the
|
||||
webapp
|
||||
*/
|
||||
char *setup_shm_region(void)
|
||||
{
|
||||
void *shared_mem_region = NULL;
|
||||
|
||||
//ID for the memory region
|
||||
int shm_id;
|
||||
|
||||
shm_unlink(SHM_KEY);
|
||||
|
||||
//Set up the shared memory region
|
||||
shm_id = shm_open(SHM_KEY, O_CREAT | O_RDWR, 0);
|
||||
if (shm_id == failure) {
|
||||
|
||||
perror("Failed to get the shared memory region");
|
||||
return (char *)shared_mem_region;
|
||||
|
||||
}
|
||||
|
||||
//Set the size of the shared memory region so we avoid bus error
|
||||
ftruncate(shm_id, SHM_SIZE);
|
||||
|
||||
//Map the shared memory region
|
||||
shared_mem_region = mmap(0, SHM_SIZE, O_RDWR, MAP_SHARED, shm_id, 0);
|
||||
if (shared_mem_region == (void *)failure) {
|
||||
|
||||
perror("SHMAT ERROR");
|
||||
shmctl(shm_id, IPC_RMID, NULL);
|
||||
shared_mem_region = NULL;
|
||||
return (char *)shared_mem_region;
|
||||
|
||||
}
|
||||
|
||||
return (char *)shared_mem_region;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
void remove_shm_region(void)
|
||||
output: int - 0 on success, -1 on failure
|
||||
|
||||
This function tears down the shared memory region
|
||||
*/
|
||||
int remove_shm_region(void *shm_region)
|
||||
{
|
||||
|
||||
//Detach the shared memory region from the process
|
||||
return shmdt(shm_region);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
int dump_data(LatencyCounter& latencies, char *region)
|
||||
input: LatencyCounter& latencies - The class that holds the current latency data
|
||||
input: char *region - The region to copy the data to.
|
||||
output: int - 0 on success, -1 on failure
|
||||
|
||||
This function will dump the latency counts and values to the shared memory region
|
||||
that the python web server will use
|
||||
*/
|
||||
int dump_data(LatencyCounter& latencies, char *region)
|
||||
{
|
||||
|
||||
//Get the shared memory region
|
||||
char *current_place = region;
|
||||
if (current_place == (char *)NULL) {
|
||||
|
||||
printf("Shared memory region is not setup\n");
|
||||
return failure;
|
||||
|
||||
}
|
||||
|
||||
//Holds the total count of the latencies so we can send percentages over
|
||||
unsigned int total_count = latencies.latenciesCount;
|
||||
|
||||
//Latency value percentage
|
||||
int percentage;
|
||||
|
||||
//First lock the semaphore so we can write
|
||||
sem_wait(web_sem);
|
||||
|
||||
//Dump the current count of the values before the percentages
|
||||
current_place += sprintf(current_place, "%u ", latencies.latenciesCount);
|
||||
|
||||
//Iterate over each value in the latencies map, placing the value in the shared memory region
|
||||
for(unordered_map<int,int>::iterator i = (*latencies.latencyValues).begin(); i != (*latencies.latencyValues).end(); i++) {
|
||||
|
||||
percentage = (i->second * 100 / total_count);
|
||||
|
||||
//Only copy the latency value if it is at least 1 percentage point to filter out outliers
|
||||
if (percentage > 0)
|
||||
|
||||
current_place += sprintf(current_place, "%d %d ", i->first, percentage);
|
||||
|
||||
}
|
||||
|
||||
sprintf(current_place, "\n");
|
||||
|
||||
sem_post(web_sem);
|
||||
|
||||
return success;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
void sig_handler(int signum)
|
||||
input: int - the signal value
|
||||
|
||||
This function will get run when a signal is sent to the process and will gracefully
|
||||
shut down the program
|
||||
*/
|
||||
void sig_handler(int signum)
|
||||
{
|
||||
|
||||
fprintf(stderr, "Received signal: %d\n", signum);
|
||||
|
||||
//Close the shared memory region now that we don't need it
|
||||
close_ivshmem_region();
|
||||
remove_shm_region(shm_addr);
|
||||
shm_addr = NULL;
|
||||
|
||||
exit(-1);
|
||||
|
||||
}
|
90
misc/sample_application/uservm/userApp.h
Normal file
90
misc/sample_application/uservm/userApp.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "ivshmemlib.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class LatencyCounter
|
||||
{
|
||||
public:
|
||||
|
||||
//A total count of the latencies
|
||||
unsigned int latenciesCount;
|
||||
|
||||
/*Used for sending the data needed for the histogram to python
|
||||
First value is the latency data point, second value is the count*/
|
||||
unordered_map<int,int> *latencyValues;
|
||||
|
||||
LatencyCounter()
|
||||
{
|
||||
latenciesCount = 0;
|
||||
latencyValues = new unordered_map<int,int>();
|
||||
}
|
||||
|
||||
~LatencyCounter()
|
||||
{
|
||||
|
||||
latenciesCount = 0;
|
||||
delete latencyValues;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
void clear(void)
|
||||
|
||||
This method clears the latency counter
|
||||
*/
|
||||
void clear(void)
|
||||
{
|
||||
|
||||
latenciesCount = 0;
|
||||
latencyValues->clear();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#define SHM_KEY "/pyservershm"
|
||||
#define SHM_ID 1337
|
||||
#define SHM_SIZE 1048576
|
||||
|
||||
#define SEM_KEY "/pyserversem"
|
||||
|
||||
#define BUFFERSIZE 256
|
||||
|
||||
//Used for synchronizing between the webserver and the data
|
||||
sem_t *web_sem;
|
||||
|
||||
//Shared memory region between userapp and webapp
|
||||
char *shm_addr;
|
||||
|
||||
//Used for holding the data from cyclictest
|
||||
char data_buffer[BUFFERSIZE] = {0};
|
||||
char *search_str;
|
||||
|
||||
char *setup_ipcomms(void);
|
||||
char *setup_shm_region(void);
|
||||
int remove_shm_region(void *);
|
||||
|
||||
int process_data(LatencyCounter&);
|
||||
int dump_data(LatencyCounter&, char *);
|
||||
|
||||
void sig_handler(int);
|
Loading…
Reference in New Issue
Block a user