blob: b54dcf1a19cd4eb7537566cad674abd60a653175 [file] [log] [blame]
/**
* Copyright (c) 2020-2021 Robert Bosch GmbH.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Robert Bosch GmbH - initial API and implementation
*/
package org.eclipse.app4mc.slg.ros2.generators
class RosAmlGenerator {
// Suppress default constructor
private new() {
throw new IllegalStateException("Utility class");
}
static def String toCpp() '''
#include "aml.h"
#include <mutex>
std::mutex lock_;
static long perf_event_define(pid_t proccess_id, int group_fd, uint64_t pinned, uint32_t event_type, uint64_t event)
{
struct perf_event_attr hw_event;
pid_t pid = proccess_id; // measure the current process/thread
int cpu = -1; // measure on any cpu
unsigned long flags = 0;
int fd_current;
memset(&hw_event, 0, sizeof(struct perf_event_attr));
hw_event.type = event_type;
hw_event.size = sizeof(struct perf_event_attr);
hw_event.config = event;
hw_event.disabled = 1; // off by default. specifies whether the counter starts out disabled or enabled.
hw_event.exclude_kernel = 1; // excluding events that happen in the kernel-space
hw_event.exclude_hv = 1; // excluding events that happen in the hypervisor
hw_event.pinned = pinned; // specifies the counter to be on the CPU if at all possible. applies only to hardware counters and only to group leaders.
hw_event.exclude_user = 0; // excludes events that happen in user space
hw_event.exclude_callchain_kernel = 1; // Do not include kernel callchains.
hw_event.exclude_callchain_user = 0; // Do not include user callchains.
// hw_event.inherit = 1; // Inherit does not work for some combinations of read_format values, such as PERF_FORMAT_GROUP.
//hw_event.exclusive = 1; // not working for counters other than cycle counter
//hw_event.exclude_idle = 1; // doesn't work
hw_event.read_format = PERF_FORMAT_GROUP; // Allows all counter values in an event group to be read with one read
fd_current = syscall(__NR_perf_event_open, &hw_event, pid, cpu, group_fd, flags);
if (fd_current == -1) {
int error_num = errno;
printf("Error opening leader %llx\n", hw_event.config);
printf("Errno error code %d\n", error_num);
exit(EXIT_FAILURE);
}
return fd_current;
}
int instrument_start(pid_t pid, uint64_t event_list[], int total_events){
lock_.lock();
static int called = 0;
static int fd;
if(!called) {
int i;
fd = perf_event_define(pid, -1, 1, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES);
//perf_event_define(pid, fd, 0, PERF_TYPE_RAW, )
for (i = 0; i < total_events; i++)
perf_event_define(pid, fd, 0, PERF_TYPE_RAW, event_list[i]);
/* Example usage:
perf_event_define(fd, 0, PERF_TYPE_RAW, 0x0008);
perf_event_define(fd, 0, PERF_TYPE_RAW, 0x0012);
perf_event_define(fd, 0, PERF_TYPE_RAW, 0x0004);
perf_event_define(fd, 0, PERF_TYPE_RAW, 0x0003);
perf_event_define(fd, 0, PERF_TYPE_RAW, 0x0016);
perf_event_define(fd, 0, PERF_TYPE_RAW, 0x0017);
int fd = perf_event_define(-1, 1, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES);
perf_event_define(fd, 0, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS);
perf_event_define(fd, 0, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
perf_event_define(fd , 0, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES);
perf_event_define(fd , 0, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES);
perf_event_define(fd , 0, PERF_TYPE_HW_CACHE, (PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16));
perf_event_define(fd , 0, PERF_TYPE_HW_CACHE, (PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16));
*/
called = 1;
}
ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
return fd;
}
struct read_format {
uint64_t nr; // The number of events
struct {
uint64_t value; // The value of the event
} values[];
};
void instrument_stop(int fd, char* filename){
ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
char buf[4096];
read(fd, buf, sizeof(buf));
int i = 0;
struct read_format* rf = (struct read_format*) buf;
FILE * file_pointer;
file_pointer = fopen(filename, "a");
for (i = 0; i < rf->nr; i++)
fprintf(file_pointer, "%" PRId64 "\t", rf->values[i].value);
fprintf(file_pointer, "\n");
fclose(file_pointer);
//close(fd);
lock_.unlock();
}
void instrument_read(int fd){
char buf[4096];
read(fd, buf, sizeof(buf));
int i;
struct read_format* rf = (struct read_format*) buf;
FILE * file_pointer;
file_pointer = fopen("output.log", "a");
for (i = 0; i < rf->nr; i++)
fprintf(file_pointer, "%" PRId64 "\t", rf->values[i].value);
fprintf(file_pointer, "\n");
fclose(file_pointer);
ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
}
void instrument_read_to_file(int fd, char* filename){
ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
char buf[4096];
read(fd, buf, sizeof(buf));
int i;
struct read_format* rf = (struct read_format*) buf;
FILE * file_pointer;
file_pointer = fopen(filename, "a");
for (i = 0; i < rf->nr; i++)
fprintf(file_pointer, "%" PRId64 "\t", rf->values[i].value);
fprintf(file_pointer, "\n");
fclose(file_pointer);
ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
}
void instrument_reset(int fd) {
ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
}
'''
static def String toH() '''
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <asm/unistd.h>
#include <inttypes.h>
#include <errno.h>
int instrument_start(pid_t pid, uint64_t event_list[], int total_events);
void instrument_stop(int fd, char* filename);
void instrument_read(int fd);
void instrument_reset(int fd);
void instrument_read_to_file(int fd, char* filename);
'''
}