https://github.com/epiqc/ScaffCC
Revision 9d2cca71cf54ddfebda26e247d82ae7b71d9e03c authored by Pranav Gokhale on 30 June 2018, 18:56:21 UTC, committed by Pranav Gokhale on 30 June 2018, 18:56:21 UTC
1 parent 720b0db
Raw File
Tip revision: 9d2cca71cf54ddfebda26e247d82ae7b71d9e03c authored by Pranav Gokhale on 30 June 2018, 18:56:21 UTC
Fix OpenQASM output formatting of Rx and Ry
Tip revision: 9d2cca7
frequency-estimation-hybrid.c
#include <stdlib.h>    /* malloc    */
#include <stdio.h>     /* printf    */
#include <stddef.h>    /* offsetof  */
#include <string.h>    /* strcpy    */
#include <stdbool.h>   /* bool      */
#include <stdint.h>    /* int64_t   */
#include "uthash.h"    /* HASH_ADD  */
#include <math.h>      /* floorf    */

#define _MAX_FUNCTION_NAME 90
#define _MAX_INT_PARAMS 4
#define _MAX_DOUBLE_PARAMS 4
#define _MAX_CALL_DEPTH 16

// DEBUG switch
bool debugFreqEstimationHybrid = false;

/*****************
* Stack Definition  
******************/
// The stack is in fact a call stack, but keeps frequencies of all previous parents
// so that a childs frequency would be multiplied by that of all before it

// elements on the stack are of type:
typedef unsigned stackElement_t;

// defining a structure to act as stack for pointer values to resources that must be updated                    
typedef struct {
  stackElement_t *contents;
  int top;
  int maxSize;
} resourcesStack_t;

// declare global "resources" array address stack
resourcesStack_t *resourcesStack = NULL;

void stackInit (int maxSize) {
  resourcesStack = (resourcesStack_t*)malloc(sizeof(resourcesStack_t));
  if (resourcesStack == NULL) {
    fprintf(stderr, "Insufficient memory to initialize stack.\n");
    exit(1);
  }
  stackElement_t *newContents;
  newContents = (stackElement_t*)malloc( sizeof(stackElement_t)*maxSize );
  if (newContents == NULL) {
    fprintf(stderr, "Insufficient memory to initialize stack.\n");
    exit(1);
  }
  resourcesStack->contents = newContents;
  resourcesStack->maxSize = maxSize;
  resourcesStack->top = -1; /* i.e. empty */ 
}

void stackDestroy() {
  free(resourcesStack->contents);
  resourcesStack->contents = NULL;
  resourcesStack->maxSize = 0;
  resourcesStack->top = -1;
}

void stackPush (stackElement_t stackElement) {
  if (resourcesStack->top >= resourcesStack->maxSize - 1) {
    fprintf (stderr, "Can't push element on stack: Stack is full.\n");
    exit(1);
  }
  // insert element and update "top"
  resourcesStack->contents[++resourcesStack->top] = stackElement;
}

void stackPop () {
  if (debugFreqEstimationHybrid)
    printf("Popping from stack\n");  
  if (resourcesStack->top < 0) {
    fprintf (stderr, "Can't pop element from stack: Stack is empty.\n");
    exit(1);    
  }

  //update "top"
  resourcesStack->top--;

}

/**********************
* Hash Table Definition
***********************/

// defining a structure that can be hashed using "uthash.h"
typedef struct {
  
  char function_name[_MAX_FUNCTION_NAME];             /* these three fields */
  int int_params[_MAX_INT_PARAMS];                    /* comprise */
  double double_params[_MAX_DOUBLE_PARAMS];           /* the key */

  // resources[0] ---> Invocation count (frequency) of module 
  // resources[1] ---> Number of integer arguments
  // resources[2] ---> Number of double arguments
  unsigned long long resources[3];                    /* hash table value field */

  UT_hash_handle hh;                                  /* make this structure hashable  */

} hash_entry_t;

// defining multi-field key for hash table
typedef struct {
  char function_name[_MAX_FUNCTION_NAME];      
  int int_params[_MAX_INT_PARAMS];             
  double double_params[_MAX_DOUBLE_PARAMS];    
} lookup_key_t;

// how many bytes long is the key?
const size_t keylen = _MAX_FUNCTION_NAME * sizeof(char)
                    + _MAX_INT_PARAMS * sizeof(int)
                    + _MAX_DOUBLE_PARAMS * sizeof(double);

// declare global memoization hash table
hash_entry_t *memos = NULL;

void print_hash_table() {
  printf("<<<---------------------------------------\n");  
  printf("current hash table:\n");
  int i;
  hash_entry_t *memo;
  for (memo=memos; memo != NULL; memo=memo->hh.next) {
    printf("%s -- ", memo->function_name);
    for (i=0; i<_MAX_INT_PARAMS; i++)
     printf("%d ", memo->int_params[i]); 
    printf("-- ");
    for (i=0; i<_MAX_DOUBLE_PARAMS; i++)
     printf("%f ", memo->double_params[i]);   
    printf("-- ");       
    for (i=0; i<3; i++)
     printf("%llu ", memo->resources[i]);   
    printf("\n"); 
  }
  printf("--------------------------------------->>>\n");  
}

/* add_memo: add entry in hash table */
void add_memo ( char *function_name,                          /* function name string */
                int *int_params, unsigned num_ints,           /* integer parameters */
                double *double_params, unsigned num_doubles,  /* double parameters */
                unsigned long long *resources                 /* resources for that function version */
                ) {             

  // allocate space for "memo" entry and
  // set "memo" space to zero to avoid random byte inconsistency in lookup 
  hash_entry_t *memo = calloc( 1, sizeof(hash_entry_t) );
  if (memo == NULL) {
    fprintf(stderr, "Insufficient memory to add memo.\n");
    exit(1);
  }  

  // copy into field of "memo"
  strcpy (memo->function_name, function_name);
  memcpy (memo->int_params, int_params, num_ints * sizeof(int));
  memcpy (memo->double_params, double_params, num_doubles * sizeof(double));
  memcpy (memo->resources, resources, 3 * sizeof(unsigned long long));
 
  // HASH_ADD (hh_name, head, keyfield_name, key_len, item_ptr)
  HASH_ADD(hh, memos, function_name, keylen, memo);
}

/* find_memo: find an entry in hash table */
hash_entry_t *find_memo ( char *function_name, 
                          int *int_params, unsigned num_ints,
                          double *double_params, unsigned num_doubles
                              ) {

  // returned entry -- NULL if not found
  hash_entry_t *memo = NULL;

  // build appropriate lookup_key object
  lookup_key_t *lookup_key = calloc(1, sizeof(lookup_key_t) );
  if (lookup_key == NULL) {
    fprintf(stderr, "Insufficient memory to create lookup key.\n");
    exit(1);
  }  
  memset (lookup_key, 0, sizeof(lookup_key_t));
  strcpy (lookup_key->function_name, function_name);
  memcpy (lookup_key->int_params, int_params, num_ints * sizeof(int));
  memcpy (lookup_key->double_params, double_params, num_doubles * sizeof(double));

  HASH_FIND (hh, memos, lookup_key, keylen, memo);
    

  //free(lookup_key->double_params);  
  //free(lookup_key->int_params);
  //free(lookup_key->function_name);
  free(lookup_key);
  lookup_key = NULL;
  return memo;
}

/* delete_memo: delete a hash table entry */
void delete_memo (hash_entry_t *memos, hash_entry_t *memo) {
  HASH_DEL (memos, memo);
  free(memo);
}

/*void delete_all_memos() {
  hash_entry_t *memo, *tmp;

  // deletion-safe iteration
  HASH_ITER(hh, memos, memo, tmp) {
    HASH_DEL(memos, memo);  
    free(memo);            
  }
}*/

/*****************************
* Functions to be instrumented
******************************/

/* memoize: memoization function */
/* A call to this function ensures that the relevant entry */
/* in the hash table has been created */
int memoize ( char *function_name, 
               int *int_params, unsigned num_ints,
               double *double_params, unsigned num_doubles,
               unsigned repeat
                              ) {

  static unsigned long long total_call_count = 0;
  total_call_count++;
  //printf("Total Call Count = %d", total_call_count);

  if (debugFreqEstimationHybrid) {
    printf("memoize called on %s !\n", function_name);
    printf("repeat value = %d !\n", repeat);
  }

  hash_entry_t *memo;
  memo = find_memo(function_name, int_params, num_ints, double_params, num_doubles);

  if (memo == NULL) {
    if (debugFreqEstimationHybrid)
      printf("NOT memoized before :(\n");
    // create entry with zero resources
    // the function call in LLVM IR will be called and will populate
    unsigned long long *resources = calloc (3, sizeof(unsigned long long));
    resources[0] = repeat;  // invocation count
    resources[1] = num_ints; // number of int args
    resources[2] = num_doubles; // number of double args

    // multiply by the frequency of all parents before this module, then add to memos table
    int it;
    unsigned long long accumulative_mult = 1;
    for (it = resourcesStack->top; it > 0; it--)
      accumulative_mult *= resourcesStack->contents[it];

    resources[0] *= accumulative_mult;

    add_memo(function_name, int_params, num_ints, double_params, num_doubles, resources);

    // push this function versions resources to the top of stack
    // will use the frequency of it to multiply all children frequencies hereafter by that frequency
    if (debugFreqEstimationHybrid)
      printf("pushing to stack: %s\n", function_name);
  }

  else {
    if (debugFreqEstimationHybrid)
      printf("Memoized already! :)\n");
    // add to the frequency of execution (repeat times)
    int it;
    unsigned long long accumulative_mult = 1;
    for (it = resourcesStack->top; it > 0; it--)
      accumulative_mult *= resourcesStack->contents[it];

    memo->resources[0] += repeat*accumulative_mult;
  }

  // put on the stack the individual frequency of this module
  stackPush(repeat); 
  
  // print updated hash table
  if (debugFreqEstimationHybrid)
    print_hash_table();

  return 0;
}

/* exit_scope: resource transfer function*/
/* A call to this function occurs after the module has been entered into the hash table*/
/* It will pop the last frequency off of the stack so it won't multiply anymore */
void exit_scope () 
{
  if (debugFreqEstimationHybrid)
    printf("exiting scope...\n");
  
  stackPop();
}

//void qasm_gate () {
//}

void qasm_initialize ()
{
  if (debugFreqEstimationHybrid)
    printf("initializing stack....\n");

  // initialize with maximum possible levels of calling depth
  stackInit(_MAX_CALL_DEPTH);
  
  // put "main" in the first row of both the hash table and the stack
    //int main_int_params[_MAX_INT_PARAMS] = {0};
    int *main_int_params = calloc (_MAX_INT_PARAMS, sizeof(int));
    //double main_double_params[_MAX_DOUBLE_PARAMS] = {0.0};
    double *main_double_params = calloc (_MAX_DOUBLE_PARAMS, sizeof(double));
    //unsigned long long main_resources[3] = {0};
    unsigned long long *main_resources = calloc (3, sizeof(unsigned long long));
    // main is executed once
    main_resources[0] = 1;

  add_memo("main                           ", main_int_params, 0, main_double_params, 0, main_resources);

  stackPush(1); 
}

void qasm_resource_summary ()
{
  // Profiling info: Total Gates, Execution Frequency, Number of Int Params, Number of Double Params
 
  int i;
  hash_entry_t *memo;
  for (memo=memos; memo != NULL; memo=memo->hh.next) {
    printf("%s ", memo->function_name);
    for (i=0; i<_MAX_INT_PARAMS; i++) {
      printf("%2d ", memo->int_params[i]); 
    }
    for (i=0; i<_MAX_DOUBLE_PARAMS; i++) {
      printf("%12f ", floorf(memo->double_params[i] * 10000 + 0.5) / 10000);   
    }
    printf("%8llu %8llu %8llu \n", memo->resources[0], memo->resources[1], memo->resources[2]);   
     
  }

  // free allocated memory for the "stack"
  stackDestroy();

  // free allocated memory for the "memos" table
  //delete_all_memos();
  HASH_CLEAR(hh,memos);
}

/*
int main () {
  
  qasm_initialize();


  // create an entry
  char *function_name = "random_func                    ";
  int int_params [3] = {1, 6, -2};
  double double_params [1] = {-3.14};
  unsigned long long resources [3] = {1,3,1};


  printf("*** main *** : memos->function_name = %s \n", memos->function_name);
  
  // insert entry
  memoize (function_name, int_params, 3, double_params, 1, 1);

  printf("*** main *** : memos->function_name = %s \n", memos->function_name);


  // find entry
  hash_entry_t *memo;
  memo = find_memo (function_name, int_params, 3, double_params, 1);
  
  if (memo == NULL)
  { printf("*** Entry not found *** \n"); return -1; }

  printf("Resources for this function: \n");
  int i;
  for (i=0; i<3; i++)
    printf("%llu, ", memo->resources[i]);
  printf("\n");

  memoize(function_name, int_params, 3, double_params, 1, 4);
  qasm_resource_summary();

  return 0;
}
*/
back to top