/* ------------------------------------------------------------------------------- * intr_latency.c * * author: Mark McDermott * Created: Jan 30, 2009 * Updated: Apr 23, 2017 For Zedboard * Updated: Feb 2, 2021 For Ultra96 * * This routine measures the average latecncy from the time an interrupt input * to the SOC occurs to when it is handled. This is used to determine how fast * the SOC can handle interrupts from the H1KP * */ //application code //take in a string through command line or a file, //write it to ocm, //take in number of bytes, //reset keccak, //start keccak to start the hashing. //detect the interrupt from sha3_done from sha3_burst_master, measure interrupt latency #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* ------------------------------------------------------------------------------- * One-bit masks for bits 0-31 */ #define ONE_BIT_MASK(_bit) (0x00000001 << (_bit)) /* -------------------------------------------------------------------------------*/ #define MAP_SIZE 4096UL #define MAP_MASK (MAP_SIZE - 1) /* ------------------------------------------------------------------------------- * Device path name for the GPIO device */ #define GPIO_DEV_PATH "/dev/gpio_int" #define GPIO_DR_NUM 0x0 // Pin Number #define GPIO_DR 0xA0050004 // Interrupt register /* ------------------------------------------------------------------------------- * Number of interrupt latency measurements to take: */ #define NUM_MEASUREMENTS 100 #define MAX_STRING_LENGTH 32 /* ------------------------------------------------------------------------------- * Array of interrupt latency measurements (in micro seconds): */ unsigned long intr_latency_measurements[NUM_MEASUREMENTS]; /* ------------------------------------------------------------------------------- * Function prototypes */ unsigned long int_sqrt(unsigned long n); void compute_interrupt_latency_stats( unsigned long *min_latency_p, unsigned long *max_latency_p, double *average_latency_p, double *std_deviation_p); /* ------------------------------------------------------------------------------- * Main routine */ int main(int argc, char *argv[]) { volatile int rc; int i; struct timeval start_timestamp; struct timeval sigio_signal_timestamp; char array[MAX_STRING_LENGTH]; /* if (argc != 3) { printf("Usage: %s \n", argv[0]); return EXIT_FAILURE; } if (strcmp(argv[1], "-s") == 0) { strcpy(array, argv[2]); } else { printf("Invalid option\n"); printf("Usage: %s \n", argv[0]); return EXIT_FAILURE; } unsigned int hex[MAX_STRING_LENGTH] = {0}; unsigned int hex_comb; int j; for (i = 0, j = 0; array[i] != '\0'; ++i) { if ((i % 8) == 0 && i != 0) j++; if (array[i] >= '0' && array[i] <= '9'){ hex[j] = hex[j] * 16 + (array[i] - '0'); } else if (array[i] >= 'a' && array[i] <= 'f') { hex[j] = hex[j] * 16 + (array[i] - 'a' + 10); } else if (array[i] >= 'A' && array[i] <= 'F') { hex[j] = hex[j] * 16 + (array[i] - 'A' + 10); } else { printf("Invalid character in input string\n"); return; } } hex_comb = hex[5] +hex[4]+ hex[3]+hex[2]+hex[1]+ hex[0]; for (int index = 0; index <= j; ++index) printf("input value : %.8x, %.8x\n", index, hex[index]); printf("input value : %.8x, %.8x\n", index, hex_comb); */ //Clock Configuration int dh = open("/dev/mem", O_RDWR | O_SYNC); if (dh == -1) { printf("Unable to open /dev/mem. Ensure it exists (major=1, minor=1)\n"); printf("Must be root to run this routine.\n"); return -1; } volatile unsigned int *apll_ctrl, *apll_cfg; volatile unsigned int *pll_status, *pl0_ref_ctrl, *pl1_ref_ctrl, *clk_reg; volatile unsigned int *apll_ctrl_v, *apll_cfg_v; volatile unsigned int *pll_status_v, *pl0_ref_ctrl_v; volatile unsigned int *pl0; volatile unsigned int *pl1; int num_bytes = 0; //number of bytes to hash pl0_ref_ctrl = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x00FF5E00C0 & ~MAP_MASK); pl1_ref_ctrl = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x00FF5E00C4 & ~MAP_MASK); apll_ctrl = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x00FD1A0020 & ~MAP_MASK); apll_cfg = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x00FD1A0024 & ~MAP_MASK); pll_status = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x00FD1A0044 & ~MAP_MASK); pl0 = pl0_ref_ctrl + ((0x00FF5E00C0 & MAP_MASK) >> 2); pl1 = pl1_ref_ctrl + ((0x00FF5E00C4 & MAP_MASK) >> 2); //set pl0 and pl1 to 100 frequency *pl0 = (1 << 24) // bit 24 enables clock | (3 << 16) // bit 23:16 is divisor 1 | (5 << 8); *pl1 = (1 << 24) // bit 24 enables clock | (3 << 16) // bit 23:16 is divisor 1 | (5 << 8); /* ------------------------------------------------------------------------- * Take interrupt latency measurements in a loop: */ for (i = 0; i < NUM_MEASUREMENTS; i++) { clock_t start_t, end_t; double total_t; // start_t = clock() (void)gettimeofday(&start_timestamp, NULL); system( "python3 ./modular_exponentiation.py 2 65537 13" ); // system( "python3 ./modular_exponentiation.py hex_comb 65537 13" ); (void)gettimeofday(&sigio_signal_timestamp, NULL); // end_t = clock(); // unsigned int timer_value_interrupt = /* --------------------------------------------------------------------- * Compute interrupt latency: */ // intr_latency_measurements[i] = timer_value_interrupt; intr_latency_measurements[i] = (sigio_signal_timestamp.tv_sec - start_timestamp.tv_sec) * 1000000 + (sigio_signal_timestamp.tv_usec - start_timestamp.tv_usec); } // End of for loop /* ------------------------------------------------------------------------- * Compute interrupt latency stats: */ unsigned long min_latency; unsigned long max_latency; double average_latency; double std_deviation; compute_interrupt_latency_stats( &min_latency, &max_latency, &average_latency, &std_deviation); /* * Print interrupt latency stats: */ printf("Minimum Latency: %lu\n" "Maximum Latency: %lu\n" "Average Latency: %f\n" "Standard Deviation: %f\n" "Number of samples: %d\n", min_latency, max_latency, average_latency, std_deviation, NUM_MEASUREMENTS); FILE *fp1; fp1 = fopen("keccak_timer_values.csv", "a"); fprintf(fp1, "%lu, %lu, %f, %f\n", min_latency, max_latency, average_latency, std_deviation); fclose(fp1); return 0; } /* ----------------------------------------------------------------------------- * Compute interrupt latency stats */ void compute_interrupt_latency_stats( unsigned long *min_latency_p, unsigned long *max_latency_p, double *average_latency_p, double *std_deviation_p) { int i; unsigned long val; unsigned long min = ULONG_MAX; unsigned long max = 0; unsigned long sum = 0; unsigned long sum_squares = 0; for (i = 0; i < NUM_MEASUREMENTS; i++) { val = intr_latency_measurements[i]; if (val < min) { min = val; } if (val > max) { max = val; } sum += val; sum_squares += val * val; } *min_latency_p = min; *max_latency_p = max; unsigned long average = (unsigned long)sum / NUM_MEASUREMENTS; unsigned long std_deviation = int_sqrt((sum_squares / NUM_MEASUREMENTS) - (average * average)); *average_latency_p = average; *std_deviation_p = std_deviation; } /* --------------------------------------------------------------- * sqrt routine */ unsigned long int_sqrt(unsigned long n) { unsigned long root = 0; unsigned long bit; unsigned long trial; bit = (n >= 0x10000) ? 1 << 30 : 1 << 14; do { trial = root + bit; if (n >= trial) { n -= trial; root = trial + bit; } root >>= 1; bit >>= 2; } while (bit); return root; } //int temp = close(fd); // if (temp == -1) // { // printf("Unable to close /dev/mem. Ensure it exists (major=1, minor=1)\n"); // return -1; // } // munmap(NULL, MAP_SIZE); // return 0;