Beispiel #1
0
void CacheQuorum::handle_get_local() {
#ifdef DEBUG
   printf("CACHE_NODE handle_get_local\n");
   print_msg_info(&(node->msg_info));
#endif
   int result;
   uint8_t key_found = FAILURE;
   std::string value = "";
   uint64_t timestamp = 0;

   // Recv get_local request from the job node
   result = recv_msg(buf, msg_info->count, MPI_UINT8_T, msg_info->src, GET_LOCAL,
         msg_info->comm, status);
   MPI_ASSERT(result == MPI_SUCCESS);

   // Parse the GetTemplate
   GetTemp get;
   GetTemplate *get_format = (GetTemplate *)buf;
   get.unpack(get_format);

   // Build the GetAckTemplate
   GetAckTemp get_ack;
   GetAckTemplate *get_ack_format = (GetAckTemplate *)node->buf;

   // Lookup the key locally
   if (cache.count(get.key) != 0) {
      Parcel parcel = cache[get.key];
      value.assign(parcel.value);
      timestamp = parcel.timestamp;
      key_found = SUCCESS;
   }

   // Pack the value string into message
   get_ack.pack(get_ack_format, get.job_num, get.job_node, get.key, value,
         timestamp, key_found);

   // Reply to the requesting job node.
   result = send_msg(node->buf, sizeof(GetAckTemplate), MPI_UINT8_T,
         get_ack.job_node, GET_LOCAL_ACK, msg_info->comm, &request);
   MPI_ASSERT(result == MPI_SUCCESS);
}
Beispiel #2
0
bool Cache::handle_push(const std::string& key, uint32_t node_id, MsgTag tag) {
   MPI_ASSERT(tag == PUSH || tag == PUSH_LOCAL);

   int result;
   uint32_t target_cache_node;

   // Translate the job node's id to the id of its cache node.
   if (node_id < job_to_cache.size()) {
      target_cache_node = job_to_cache[node_id];
   }
   // If the node_id is bogus, return false.
   else {
      return false;
   }

   MsgTag recv_tag = tag == PUSH ? PUSH_ACK : PUSH_LOCAL_ACK;

   // Pack the get message into buf prior to sending.
   PushTemp push;
   PushTemplate *format = (PushTemplate *)buf;
   push.pack(format, job_num, local_rank, target_cache_node, key);

#ifdef DEBUG
   if (recv_tag == PUSH) {
      printf("Job %d Rank %d calling push on key %s to node %d!\n", job_num,
            local_rank, key.c_str(), node_id);
   }
   else {
      printf("Job %d Rank %d calling push_local on key %s to node %d!\n", job_num,
            local_rank, key.c_str(), node_id);
   }
#endif

   result = send_msg(buf, sizeof(PushTemplate), MPI_UINT8_T, coord_rank,
         tag, parent_comm, &request);

   if (result != MPI_SUCCESS) {
      return false;
   }

   result = recv_msg(buf, sizeof(PushAckTemplate), MPI_UINT8_T, MPI_ANY_SOURCE,
         recv_tag, parent_comm, &status);

   if (result != MPI_SUCCESS) {
      return false;
   }

   PushAckTemplate *temp = (PushAckTemplate *)buf;

   return temp->result == SUCCESS ? true : false;
}
Beispiel #3
0
void CacheQuorum::handle_push_local_ack() {
#ifdef DEBUG
   printf("CACHE_NODE handle_push_local_ack\n");
   print_msg_info(&(node->msg_info));
#endif
   int result;

   result = recv_msg(buf, msg_info->count, MPI_UINT8_T, msg_info->src,
         PUSH_LOCAL_ACK, msg_info->comm, status);
   MPI_ASSERT(result == MPI_SUCCESS);

   PutAckTemplate *put_ack = (PutAckTemplate *)buf;

   put_ack->result = SUCCESS;
   uint32_t job_num = put_ack->job_num;
   uint32_t job_node = put_ack->job_node;

   MPI_Comm job_comm = node->job_to_comms[job_num].job;

   // Reply back to original job node with outcome.
   result = send_msg(buf, sizeof(PushAckTemplate), MPI_UINT8_T, job_node,
         PUSH_LOCAL_ACK, job_comm, &request);
   MPI_ASSERT(result == MPI_SUCCESS);
}
Beispiel #4
0
bool Cache::handle_get(const std::string& key, std::string& value, MsgTag tag) {
   MPI_ASSERT(tag == GET || tag == GET_LOCAL);

   int result;
   uint64_t timestamp;
   get_timestamp(&timestamp);

   MsgTag recv_tag = tag == GET ? GET_ACK : GET_LOCAL_ACK;

   // Pack the get message into buf prior to sending.
   GetTemp get;
   GetTemplate *format = (GetTemplate *)buf;
   get.pack(format, job_num, local_rank, key, timestamp);

#ifdef DEBUG
   if (recv_tag == GET) {
      printf("Job %d Rank %d calling get on key %s!\n", job_num, local_rank,
            key.c_str());
   }
   else {
      printf("Job %d Rank %d calling get_local on key %s!\n", job_num,
            local_rank, key.c_str());
   }
#endif

   result = send_msg(buf, sizeof(GetTemplate), MPI_UINT8_T, coord_rank,
         tag, parent_comm, &request);

   if (result != MPI_SUCCESS) {
      return false;
   }

   result = recv_msg(buf, sizeof(GetAckTemplate), MPI_UINT8_T, coord_rank,
         recv_tag, parent_comm, &status);

   if (result != MPI_SUCCESS) {
      return false;
   }

   GetAckTemplate *temp = (GetAckTemplate *)buf;

   value.clear();
   value.assign((const char *)temp->value, temp->value_size);

   return (temp->value_size > 0) ? true : false;
}
Beispiel #5
0
bool Cache::handle_put(const std::string& key, const std::string& value,
      MsgTag tag) {

   MPI_ASSERT(tag == PUT || tag == PUT_LOCAL);

   int32_t result;
   MPI_Status status;
   MsgTag recv_tag = tag == PUT ? PUT_ACK : PUT_LOCAL_ACK;
   uint64_t timestamp;
   get_timestamp(&timestamp);

   // Pack the put message into buf prior to sending.
   PutTemp put;
   PutTemplate *format = (PutTemplate *)buf;
   put.pack(format, job_num, local_rank, coord_rank, key, value, timestamp);

#ifdef DEBUG
   if (tag == PUT) {
      printf("Job %d Rank %d calling put on %s/%s!\n", job_num, local_rank,
            key.c_str(), value.c_str());
   }
   else {
      printf("Job %d Rank %d calling put_local on %s/%s!\n", job_num,
            local_rank, key.c_str(), value.c_str());
   }
#endif

   result = send_msg(buf, sizeof(PutTemplate), MPI_UINT8_T, coord_rank, tag,
         parent_comm, &request);

   if (result != MPI_SUCCESS) {
      return false;
   }

   // Assuming this cache is not doing any non-blocking calls, and as a result
   // this PUT_ACK/PUT_LOCAL_ACK is guaranteed to be the ack for the send we
   // just made. This assumption would not hold if this cache did non-blocking
   // IO.
   result = recv_msg(buf, sizeof(PutAckTemplate), MPI_UINT8_T, coord_rank,
         recv_tag, parent_comm, &status);

   return result == MPI_SUCCESS ? true : false;
}
Beispiel #6
0
void LeaderNode::handle_requests() {
#ifdef DEBUG
   printf("LeaderNode entering handle_requests!\n");
#endif
   while (true) {
      while (msg_ready() == false) {
         message_select();
      }

      while (msg_ready() == true) {
         msg_info = msg_queue.front();
         msg_queue.pop_front();
#ifdef DEBUG
         printf("msg_queue.size: %u\n", msg_queue.size());
#endif

         switch (msg_info.tag) {
            case SPAWN_JOB:
               handle_spawn_job();
               break;

            case SPAWN_CACHE:
               handle_spawn_cache();
               break;

            case EXIT:
               handle_exit();
               break;

            case EXIT_ACK:
               handle_exit_ack();
               break;

            default:
               printf("===== DEFAULT =====\n");
               printf("LeaderNode %d\n", local_rank);
               print_msg_info(&msg_info);
               MPI_ASSERT(FAILURE);
               break;
         }
      }
   }
}
Beispiel #7
0
void CacheQuorum::handle_get() {
#ifdef DEBUG
   printf("CACHE_NODE handle_get\n");
   print_msg_info(&(node->msg_info));
#endif
   fprintf(stderr, "CacheQuorum handle_get not implemented!\n");
   MPI_ASSERT(FAILURE);
   /*
      int result;

      result = recv_msg(buf, msg_info->count, MPI_UINT8_T, msg_info->src, GET,
      msg_info->comm, status);
      MPI_ASSERT(result == MPI_SUCCESS);

      GetTemplate *format = (GetTemplate *)buf;

   // Build a GetReq for this key/value lookup so the cache nodes can vote as a
   // whole and achieve consistency.
   GetReq get_req;
   get_req.job_num = format->job_num;
   get_req.job_node = format->job_node;
   get_req.key = std::string(format->key, format->key + format->key_size);

   // Set max voter size and upate later when the cache_node hears back from 
   // its coord_swing node.
   get_req.votes_req = node->local_size;
   get_req.census = std::vector<Parcel>();

   // If this cache node has the key, put it inside the GetReq's census vector.
   if (cache.count(get_req.key) != 0) {
   get_req.census.push_back(cache[get_req.key]);
   }

   // Add the GetReq to the vector of pending requests for this cache node.
   pending_get_requests.push_back(get_req);

   // Pass on the GET message to this cache node's coordinator swing node.
   result = send_msg(buf, msg_info->count, MPI_UINT8_T, node->coord_rank, GET,
   node->parent_comm, &request);
   MPI_ASSERT(result == MPI_SUCCESS);
   */
}
Beispiel #8
0
void CacheQuorum::handle_push_local() {
#ifdef DEBUG
   printf("CACHE_NODE handle_push_local\n");
   print_msg_info(&(node->msg_info));
#endif
   int result;

   // Recv push_local message from job node.
   result = recv_msg(buf, msg_info->count, MPI_UINT8_T, msg_info->src,
         PUSH_LOCAL, msg_info->comm, status);
   MPI_ASSERT(result == MPI_SUCCESS);

   // If this came from a cache node
   if (msg_info->comm == MPI_COMM_WORLD) {
      parse_and_save_push_local(buf, msg_info); 
   }
   // If this came from a job node
   else {
      push_to_target_node(buf, msg_info);
   }
}
Beispiel #9
0
void LeaderNode::stdin_select() {
   // Create zeroed timeval struct for select call
   struct timeval tv;
   tv.tv_sec = 0;
   tv.tv_usec = 0; 

   // Create fd_set with STDIN for select call
   fd_set rdfds;
   FD_ZERO(&rdfds);
   FD_SET(STDIN, &rdfds);

   // Check for input on STDIN
   int stdin_ready = select(STDIN + 1, &rdfds, NULL, NULL, &tv);
   MPI_ASSERT(stdin_ready >= 0);

   // If the user input a command, parse it and add it to the message queue if
   // the command is valid.
   if (FD_ISSET(STDIN, &rdfds)) {
      FD_CLR(STDIN, &rdfds);
      // TODO: For now, assume input means kill all processes. Extend this later
      // using getops and some form of syntax.
      handle_stdin();
   }
}
Beispiel #10
0
void CacheQuorum::handle_collect() {
   fprintf(stderr, "CacheQuorum handle_collect not implemented!\n");
   MPI_ASSERT(FAILURE);
}
Beispiel #11
0
// TODO: Shouldn't need this, but include for completeness
void CacheQuorum::handle_get_local_ack() {
   fprintf(stderr, "CacheQuorum cache_node_handle_get_local_ack not implemented!\n");
   MPI_ASSERT(1 == 0);
}
Beispiel #12
0
void Cache::allocate() {
   buf = (uint8_t *)calloc(INITIAL_BUF_SIZE, sizeof(uint8_t)); 
   MPI_ASSERT(buf != NULL);
}
Beispiel #13
0
void Cache::get_owners(const std::string& key, std::vector<uint32_t>& owners) {
   fprintf(stderr, "get_owners not implemented!\n");
   MPI_ASSERT(FAILURE);
}
Beispiel #14
0
bool Cache::collect(const std::string& key) {
   fprintf(stderr, "collect not implemented!\n");
   MPI_ASSERT(FAILURE);
   return false;
}
Beispiel #15
0
void CacheQuorum::handle_get_ack() {
#ifdef DEBUG
   printf("CACHE_NODE handle_get_ack\n");
   print_msg_info(&(node->msg_info));
#endif
   fprintf(stderr, "CacheQuorum handle_get not implemented!\n");
   MPI_ASSERT(FAILURE);

   /*
      int result;

      result = recv_msg(buf, msg_info->count, MPI_UINT8_T, msg_info->src, GET_ACK,
      msg_info->comm, status);
      MPI_ASSERT(result == MPI_SUCCESS);

   // Iterator to find the GetReq that matches this get_ack.
   std::vector<GetReq>::iterator it;

   // If this is a message from this cache_node's coordinator swing_node
   if (msg_info->comm == node->parent_comm && msg_info->src == node->coord_rank) {
#ifdef DEBUG
printf("CacheNode %d got CensusTemplate from Swing Node!\n",\
node->local_rank);
#endif
   // Build out the match for the GetReq entry from the message.
   CensusTemplate *format = (CensusTemplate *)buf;
   GetReq updated_vote;
   updated_vote.job_num = format->job_num;
   updated_vote.job_node = format->job_node;
   updated_vote.key =
   std::string(format->key, format->key + format->key_size);

   // Match the GetReq object to an entry in pending_get_requests.
   it = std::find(pending_get_requests.begin(), pending_get_requests.end(),
   updated_vote);

   if (it == pending_get_requests.end()) {
   // This should never happen so abort.
   MPI_ASSERT(FAILURE);
   }
   else {
   // Update the votes_required
   it->votes_req = format->votes_req;
   }
   }
   else {
#ifdef DEBUG
printf("CacheNode %d got vote from CacheNode %d!\n", node->local_rank,
msg_info->src);
#endif
GetReq new_vote;
GetAckTemplate *format = (GetAckTemplate *)buf;
new_vote.job_num = format->job_num;
new_vote.job_node = format->job_node;
new_vote.key =
std::string(format->key, format->key + format->key_size);

   // Match the GetReq object to an entry in pending_get_requests.
   it = std::find(pending_get_requests.begin(), pending_get_requests.end(),
   new_vote);

   if (it == pending_get_requests.end()) {
   // This should never happen so abort.
   MPI_ASSERT(FAILURE);
   }
   else {
   // Add the new value to the vector of votes.
   Parcel vote;
   vote.value = std::string (format->value,
   format->value + format->value_size);
   vote.timestamp = format->timestamp;
   it->census.push_back(vote);
   }
   }

   if (it->votes_req == it->census.size()) {
#ifdef DEBUG
printf("CacheNode %d - key %s - received all %d votes!\n",
node->local_rank, it->key.c_str(), it->census.size());
#endif
   send_job_node_get_ack(it);
   pending_get_requests.erase(it);
}
#ifdef DEBUG
else {
   printf("CacheNode %d - key %s - votes %d/%u\n", node->local_rank,
         it->key.c_str(), it->census.size(), it->votes_req);
}
#endif
*/
}
Beispiel #16
0
void CacheQuorum::handle_pull() {
   fprintf(stderr, "CacheQuorum handle_pull not implemented!\n");
   MPI_ASSERT(1 == 0);
}
int main(int argc, char * argv[])
{
    int provided;
    MPI_ASSERT(MPI_Init_thread(&argc, &argv, MPI_THREAD_SINGLE, &provided));

    int rank, size;
    MPI_ASSERT(MPI_Comm_rank(MPI_COMM_WORLD, &rank));
    MPI_ASSERT(MPI_Comm_size(MPI_COMM_WORLD, &size));

    int logn = (argc>1) ? atoi(argv[1]) : 32;
    size_t count = (size_t)1<<logn; /* explicit cast required */
    printf("count = %zu \n", count );

    MPI_Datatype bigtype;
    MPI_ASSERT(MPIX_Type_contiguous_x( (MPI_Count)count, MPI_CHAR, &bigtype));
    MPI_ASSERT(MPI_Type_commit(&bigtype));

    char * rbuf = NULL;
    char * sbuf = NULL;

#ifdef USE_MPI_ALLOC_MEM
    MPI_ASSERT(MPI_Alloc_mem( (MPI_Aint)count * sizeof(char), MPI_INFO_NULL, &rbuf));
    MPI_ASSERT(MPI_Alloc_mem( (MPI_Aint)count * sizeof(char), MPI_INFO_NULL, &sbuf));
#else
    rbuf = malloc( count * sizeof(char));
    assert(rbuf!=NULL);
    sbuf = malloc( count * sizeof(char));
    assert(sbuf!=NULL);
#endif

    for (size_t i=0; i<count; i++)
        rbuf[i] = 'a';
    for (size_t i=0; i<count; i++)
        sbuf[i] = 'z';

    MPI_Request requests[2];
    MPI_Status statuses[2];

    if (rank==(size-1)) {
        MPI_ASSERT(MPI_Irecv(rbuf, 1, bigtype, 0,      0, MPI_COMM_WORLD, &(requests[1]) ));
    }
    if (rank==0) {
        MPI_ASSERT(MPI_Isend(sbuf, 1, bigtype, size-1, 0, MPI_COMM_WORLD, &(requests[0]) ));
    }

    MPI_Count ocount[2];

    if (size==1) {
        MPI_ASSERT(MPI_Waitall(2, requests, statuses));
        MPI_ASSERT(MPI_Get_elements_x( &(statuses[1]), MPI_CHAR, &(ocount[1])));
    }
    else {
        if (rank==(size-1)) {
            MPI_ASSERT(MPI_Wait( &(requests[1]), &(statuses[1]) ));
            MPI_ASSERT(MPI_Get_elements_x( &(statuses[1]), MPI_CHAR, &(ocount[1]) ));
        } else if (rank==0) {
            MPI_ASSERT(MPI_Wait( &(requests[0]), &(statuses[0]) ));
            MPI_ASSERT(MPI_Get_elements_x( &(statuses[0]), MPI_CHAR, &(ocount[0]) ));
        }
    }

    if (rank==0) {
        printf("ocount[0] = %lld \n", ocount[0]);
    } else if ( rank==(size-1) ) {
        printf("ocount[1] = %lld \n", ocount[1]);
    }

    /* correctness check */
    if (rank==(size-1)) {
        MPI_Count errors = 0;
        for (MPI_Count i=0; i<count; i++)
            errors += ( rbuf[i] != 'z' );
        printf("errors = %lld \n", errors);
    }

#ifdef USE_MPI_ALLOC_MEM
    MPI_ASSERT(MPI_Free_mem(rbuf));
    MPI_ASSERT(MPI_Free_mem(sbuf));
#else
    free(rbuf);
    free(sbuf);
#endif

    MPI_ASSERT(MPI_Type_free(&bigtype));

    MPI_ASSERT(MPI_Finalize());

    return 0;
}
Beispiel #18
0
bool Cache::pull_local(const std::string& key, uint32_t node_id) {
   fprintf(stderr, "pull_local not implemented!\n");
   MPI_ASSERT(FAILURE);
   return false;
}
Beispiel #19
0
void CacheQuorum::handle_drop_local_ack() {
   fprintf(stderr, "CacheQuorum handle_drop_local_ack not implemented!\n");
   MPI_ASSERT(FAILURE);
}
Beispiel #20
0
void CacheQuorum::handle_gather() {
   fprintf(stderr, "CacheQuorum handle_gather not implemented!\n");
   MPI_ASSERT(FAILURE);
}
Beispiel #21
0
void CacheQuorum::handle_scatter_local() {
   fprintf(stderr, "CacheQuorum handle_scatter_local not implemented!\n");
   MPI_ASSERT(FAILURE);
}
Beispiel #22
0
bool Cache::drop_local(const std::string& key) {
   fprintf(stderr, "drop not implemented!\n");
   MPI_ASSERT(FAILURE);
   return false;
}
Beispiel #23
0
void CacheQuorum::handle_get_owners_ack() {
   fprintf(stderr, "CacheQuorum handle_get_owners_ack not implemented!\n");
   MPI_ASSERT(FAILURE);
}
Beispiel #24
0
int
main(int argc, char** argv)
{
  int rc;

  char* filename = "tests/mpi-io.data";
  MPI_File file;

  MPI_Init(&argc, &argv);

  int mpi_size;
  MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
  int mpi_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);

  printf("mpi: %i/%i\n", mpi_rank, mpi_size);

  MPI_Offset size = 100;

  if (mpi_rank == 0)
  {
    struct stat s;
    rc = stat(filename, &s);
    size = s.st_size;
  }
  MPI_Bcast(&size, sizeof(MPI_Offset), MPI_BYTE, 0, MPI_COMM_WORLD);
  int size_int = (int) size;
  printf("file size: %i\n", size_int);

  int chunk_size = 4;
  MPI_Datatype chunk;
  rc = MPI_Type_contiguous(chunk_size, MPI_BYTE, &chunk);
  MPI_ASSERT(rc);
  MPI_Type_commit(&chunk);

  int chunks = (int)size/chunk_size + 1;
  MPI_Datatype strides;
  //  rc = MPI_Type_vector(chunks, chunk_size, mpi_size*chunk_size,
  //		       MPI_BYTE, &strides);
  rc = MPI_Type_vector(chunks, 1, 2, chunk, &strides);
  MPI_ASSERT(rc);
  MPI_Type_commit(&strides);

  rc = MPI_File_open(MPI_COMM_WORLD, filename,
		     MPI_MODE_RDONLY,
		     MPI_INFO_NULL, &file);
  MPI_ASSERT_MSG(rc, "could not open file");

  int disp = mpi_rank*chunk_size;
  rc = MPI_File_set_view(file, disp, MPI_BYTE, strides,
			 "native", MPI_INFO_NULL);
  MPI_ASSERT(rc);

  char buffer[10000]; // [chunk_size];
  memset(buffer, '\0', 10000);

  printf("read\n");

  MPI_Status status;

  rc = MPI_File_read_all(file, buffer, chunk_size*2, MPI_BYTE, &status);
  MPI_ASSERT(rc);
  int r;
  MPI_Get_count(&status, MPI_BYTE, &r);
  printf("r: %i\n", r);

  // printf("c: '%c'\n", buffer[0]);
  printf("c: '%s'\n", buffer);
  // MPI_File_seek(file, chunk_size, MPI_SEEK_CUR);

  // rc = MPI_File_set_view(

  MPI_Type_free(&strides);
  MPI_Type_free(&chunk);

  MPI_Finalize();

  return 0;
}
Beispiel #25
0
static void ExecuteStatement(GNode* node, gpointer data)
{
	Statement* stmt = (Statement*) node->data;
	Verbose("* Visiting GNode at level %d", g_node_depth(node));

	if (parseOnly && (stmt->type < STMT_REPEAT)) return;

	switch (stmt->type) {
		case STMT_ASSIGN: {
			ExpressionStatus status[2];
			ParameterList* paramList = stmt->parameters;
			gchar* varident = param_string_get(paramList, 0, &status[0]);
			Expression* expression = param_index_get(paramList, 1);

			// evaluator error check
			if (status[0] != STATUS_EVAL_OK) {
				Error("Malicious assign parameters! (status = %s)", expr_status_to_string(status[0]));
			}

			switch (expression->type) {
				case EXPR_RICH_INT:
				case EXPR_CONSTANT_INT: {
					Verbose("~ Executing STMT_ASSIGN: variable = %s, type = INT", varident);
					glong result = param_int_get(paramList, 1, &status[1]);

					// evaluator error check
					if (status[1] != STATUS_EVAL_OK) {
						Error("Malicious assign parameters! (status = %s)", expr_status_to_string(status[1]));
					}

					var_set_value(varident, VAR_INT, &result);
					break;
				}

				case EXPR_RICH_STRING:
				case EXPR_CONSTANT_STRING: {
					Verbose("~ Executing STMT_ASSIGN: variable = %s, type = STRING", varident);
					gchar* result_raw = param_string_get(paramList, 1, &status[1]);

					// evaluator error check
					if (status[1] != STATUS_EVAL_OK) {
						Error("Malicious assign parameters! (status = %s)", expr_status_to_string(status[1]));
					}

					gchar* result = var_replace_substrings(result_raw);

					var_set_value(varident, VAR_STRING, result);
					g_free(result_raw);
					g_free(result);
					break;
				}

				default: Error("Expression type %d not supported in assign statement!\n", expression->type);
			}

			g_free(varident);
			break;
		}

		case STMT_REPEAT: {
			ExpressionStatus status[2];
			ParameterList* paramList = stmt->parameters;
			gchar* varident = param_string_get(paramList, 0, &status[0]);
			glong i, loopCount = param_int_get(paramList, 1, &status[1]);

			Verbose("~ Executing STMT_REPEAT: variable = %s, loopCount = %ld", varident, loopCount);

			g_assert(loopCount >= 0);

			// evaluator error check
			if (!expr_status_assert(status, 2)) {
				backtrace(stmt);
				Error("Malicious repeat parameters! (%s:%d)", __FILE__, __LINE__);
			}

			for (i=0; i<loopCount; i++) {
				var_set_value(varident, VAR_INT, &i);
				g_node_children_foreach(node, G_TRAVERSE_ALL, &ExecuteStatement, NULL);
			}

			var_destroy(varident);
			g_free(varident);
			break;
		}

		case STMT_TIME: {
			Verbose("~ Executing STMT_TIME: label = %s", stmt->label);

			static gint timeId = 0;
			gdouble time;
			GTimer* timer = g_timer_new();

			g_node_children_foreach(node, G_TRAVERSE_ALL, &ExecuteStatement, NULL);

			g_timer_stop(timer);
			time = g_timer_elapsed(timer, NULL);
			g_timer_destroy(timer);

			gchar* label = var_replace_substrings(stmt->label);
			timeList = g_slist_prepend(timeList, timeevent_new(timeId++, label, time));
			g_free(label);
			break;
		}

		case STMT_CTIME: {
			Verbose("~ Executing STMT_CTIME: label = %s", stmt->label);

			static gint coreTimeId = 0;
			gchar* label = var_replace_substrings(stmt->label);
			CoreTimeEvent* coreTimeEvent = coretime_event_new(coreTimeId++, label, coretime_new(0, 0));
			coreTimeStack = g_list_prepend(coreTimeStack, coreTimeEvent);

			g_node_children_foreach(node, G_TRAVERSE_ALL, &ExecuteStatement, NULL);

			coreTimeList = g_slist_prepend(coreTimeList, coreTimeEvent);
			coreTimeStack = g_list_remove_link(coreTimeStack, g_list_first(coreTimeStack));
			g_free(label);
			break;
		}

#ifdef HAVE_MPI
		case STMT_GROUP: {
			Verbose("~ Executing STMT_GROUP: group = %s", stmt->label);

			GroupBlock* groupBlock = g_hash_table_lookup(groupMap, stmt->label);

			if(groupBlock && groupBlock->member) {
				groupStack = g_list_prepend(groupStack, groupBlock);
				g_node_children_foreach(node, G_TRAVERSE_ALL, &ExecuteStatement, NULL);
				groupStack = g_list_remove_link(groupStack, g_list_first(groupStack));
			}
			else if(!groupBlock) {
				backtrace(stmt);
				Error("Group \"%s\" doesn't exist!", stmt->label);
			}
			break;
		}

		case STMT_MASTER: {
			GroupBlock* groupBlock;
			MPI_Comm comm = MPI_COMM_WORLD;
			if(groupStack) {
				groupBlock = (GroupBlock*) g_list_first(groupStack)->data;
				comm = groupBlock->mpicomm;
			}

			gint groupRank;
			MPI_ASSERT(MPI_Comm_rank(comm, &groupRank), "Master Statement", TRUE)

			if(groupStack) Verbose("~ Executing STMT_MASTER: rank = %d, type = implicit group", groupRank);
			else           Verbose("~ Executing STMT_MASTER: rank = %d, type = world", groupRank);

			if(groupRank == MASTER) {
				g_node_children_foreach(node, G_TRAVERSE_ALL, &ExecuteStatement, NULL);
			}
			else Verbose("Im not the master here... groupRank = %d", groupRank);
			break;
		}

		case STMT_BARRIER: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			gchar* groupName = param_string_get_optional(paramList, 0, &status[0], NULL);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			GroupBlock* groupBlock = groupblock_get(groupName);

			if(groupName)  Verbose("~ Executing STMT_BARRIER: type = explicit group, name = %s", groupName);
			else           Verbose("~ Executing STMT_BARRIER: type = implicit active group");

			MPI_ASSERT(MPI_Barrier(groupBlock->mpicomm), "Barrier Statement", TRUE)

			g_free(groupName);
			break;
		}
#endif

		case STMT_SLEEP: {
			if (agileMode) return;
			Verbose("~ Executing STMT_SLEEP");

			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			glong time = param_int_get(paramList, 0, &status[0]);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			g_usleep(time);
			//sleep(time);
			break;
		}

		case STMT_BLOCK: {
			Verbose("~ Executing STMT_BLOCK");
			g_node_children_foreach(node, G_TRAVERSE_ALL, &ExecuteStatement, NULL);
			break;
		}

		case STMT_PRINT: {
			Verbose("~ Executing STMT_PRINT");

			ParameterList* paramList = stmt->parameters;
			GString* buffer = g_string_new("");
			ExpressionStatus status;
			gint i;

			for (i=0; i<paramList->len; i++) {
				gchar* string = param_string_get(paramList, i, &status);
				if (status == STATUS_EVAL_OK) {
					g_string_append(buffer, string);
					g_free(string);
					if (i < (paramList->len-1))
						g_string_append(buffer, " ");
				}
				else {
					backtrace(stmt);
					Error("Error during print parameter evaluation (index=%d, status=%s).\n",
							i, expr_status_to_string(status));
				}
			}

			gchar* processed = var_replace_substrings(buffer->str);
			g_printf("[%d] %s\n", rank, processed);
			g_free(processed);
			g_string_free(buffer, TRUE);
			break;
		}

		case STMT_FCREAT: {
			ExpressionStatus status[2];
			ParameterList* paramList = stmt->parameters;
			gchar* fhname = param_string_get(paramList, 0, &status[0]);
			gchar* fname_raw = param_string_get(paramList, 1, &status[1]);

			Verbose("~ Executing STMT_FCREAT: fhname = %s, fname = %s", fhname, fname_raw);

			// evaluator error check
			if (!expr_status_assert(status, 2)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			File* file;
			IOStatus ioStatus = iio_fcreat(fname, &file);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success) {
				Verbose("  > file = %p", file);
				var_set_value(fhname, VAR_FILE, &file);
				statementsSucceed[STMT_FCREAT]++;
			}
			else
				statementsFail[STMT_FCREAT]++;

			g_free(fhname);
			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_FOPEN: {
			ExpressionStatus status[3];
			ParameterList* paramList = stmt->parameters;
			gchar* fhname = param_string_get(paramList, 0, &status[0]);
			gchar* fname_raw = param_string_get(paramList, 1, &status[1]);
			gint   flags = param_int_get(paramList, 2, &status[2]);

			Verbose("~ Executing STMT_FOPEN: fhname = %s, fname = %s, flags = %d", fhname, fname_raw, flags);

			// evaluator error check
			if (!expr_status_assert(status, 3)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			File* file;
			IOStatus ioStatus = iio_fopen(fname, flags, &file);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success) {
				Verbose("  > file = %p", file);
				var_set_value(fhname, VAR_FILE, &file);
				statementsSucceed[STMT_FOPEN]++;
			}
			else
				statementsFail[STMT_FOPEN]++;

			g_free(fhname);
			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_FCLOSE: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			File* file = param_file_get(paramList, 0, &status[0]);

			Verbose("~ Executing STMT_FCLOSE: file = %p", file);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			g_assert(file);

			IOStatus ioStatus = iio_fclose(file);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success) {
				gchar* fhname = (gchar*) param_value_get(paramList, 0);
				var_destroy(fhname);
				statementsSucceed[STMT_FCLOSE]++;
			}
			else
				statementsFail[STMT_FCLOSE]++;
			break;
		}

		case STMT_FREAD: {
			ExpressionStatus status[3];
			ParameterList* paramList = stmt->parameters;
			File* file = param_file_get(paramList, 0, &status[0]);
			glong dataSize = param_int_get_optional(paramList, 1, &status[1], READALL);
			glong offset = param_int_get_optional(paramList, 2, &status[2], OFFSET_CUR);

			Verbose("~ Executing STMT_FREAD: file = %p, dataSize = %ld, offset = %ld", file, dataSize, offset);

			// evaluator error check
			if (!expr_status_assert(status, 3)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			IOStatus ioStatus = iio_fread(file, dataSize, offset);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_FREAD]++;
			else
				statementsFail[STMT_FREAD]++;
			break;
		}

		case STMT_FWRITE: {
			ExpressionStatus status[3];
			ParameterList* paramList = stmt->parameters;
			File* file = param_file_get(paramList, 0, &status[0]);
			glong dataSize = param_int_get(paramList, 1, &status[1]);
			glong offset = param_int_get_optional(paramList, 2, &status[2], -1);

			Verbose("~ Executing STMT_FWRITE: file = %p, dataSize = %ld, offset = %ld", file, dataSize, offset);

			// evaluator error check
			if (!expr_status_assert(status, 3)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			IOStatus ioStatus = iio_fwrite(file, dataSize, offset);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_FWRITE]++;
			else
				statementsFail[STMT_FWRITE]++;
			break;
		}

		case STMT_FSEEK: {
			ExpressionStatus status[3];
			ParameterList* paramList = stmt->parameters;
			File* file = param_file_get(paramList, 0, &status[0]);
			glong offset = param_int_get(paramList, 1, &status[1]);
			gint whence = param_int_get_optional(paramList, 2, &status[2], SEEK_SET);

			Verbose("~ Executing STMT_FSEEK: file = %p, offset = %ld, whence = %d", file, offset, whence);

			// evaluator error check
			if (!expr_status_assert(status, 3)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			IOStatus ioStatus = iio_fseek(file, offset, whence);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_FSEEK]++;
			else
				statementsFail[STMT_FSEEK]++;
			break;
		}

		case STMT_FSYNC: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			File* file = param_file_get(paramList, 0, &status[0]);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			IOStatus ioStatus = iio_fsync(file);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_FSYNC]++;
			else {
				statementsFail[STMT_FSYNC]++;
			}
			break;
		}

		case STMT_WRITE: {
			ExpressionStatus status[3];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);
			glong  dataSize = param_int_get(paramList, 1, &status[1]);
			glong  offset = param_int_get_optional(paramList, 2, &status[2], 0);

			Verbose("~ Executing STMT_WRITE: file = %s, dataSize = %ld, offset = %ld", fname_raw, dataSize, offset);

			// evaluator error check
			if (!expr_status_assert(status, 3)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			IOStatus ioStatus = iio_write(fname, dataSize, offset);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_WRITE]++;
			else
				statementsFail[STMT_WRITE]++;

			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_APPEND: {
			ExpressionStatus status[2];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);
			glong  dataSize = param_int_get(paramList, 1, &status[1]);

			Verbose("~ Executing STMT_APPEND: file = %s, dataSize = %ld", fname_raw, dataSize);

			// evaluator error check
			if (!expr_status_assert(status, 2)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			IOStatus ioStatus = iio_append(fname, dataSize);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_APPEND]++;
			else
				statementsFail[STMT_APPEND]++;

			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_READ: {
			ExpressionStatus status[3];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);
			glong  dataSize = param_int_get_optional(paramList, 1, &status[1], READALL);
			glong  offset = param_int_get_optional(paramList, 2, &status[2], 0);

			Verbose("~ Executing STMT_READ: file = %s, dataSize = %ld, offset = %ld",
					fname_raw, dataSize, offset);

			// evaluator error check
			if (!expr_status_assert(status, 2)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			IOStatus ioStatus = iio_read(fname, dataSize, offset);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_READ]++;
			else
				statementsFail[STMT_READ]++;

			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_LOOKUP: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);

			Verbose("~ Executing STMT_LOOKUP: file = %s", fname_raw);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			IOStatus ioStatus = iio_lookup(fname);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_LOOKUP]++;
			else
				statementsFail[STMT_LOOKUP]++;

			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_DELETE: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);

			Verbose("~ Executing STMT_DELETE: file = %s", fname_raw);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			IOStatus ioStatus = iio_delete(fname);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_DELETE]++;
			else
				statementsFail[STMT_DELETE]++;

			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_MKDIR: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);

			Verbose("~ Executing STMT_MKDIR: file = %s", fname_raw);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			IOStatus ioStatus = iio_mkdir(fname);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_MKDIR]++;
			else
				statementsFail[STMT_MKDIR]++;

			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_RMDIR: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);

			Verbose("~ Executing STMT_RMDIR: file = %s", fname_raw);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			IOStatus ioStatus = iio_rmdir(fname);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_RMDIR]++;
			else
				statementsFail[STMT_RMDIR]++;

			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_CREATE: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);

			Verbose("~ Executing STMT_CREATE: file = %s", fname_raw);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			IOStatus ioStatus = iio_create(fname);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_CREATE]++;
			else
				statementsFail[STMT_CREATE]++;

			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_STAT: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);

			Verbose("~ Executing STMT_STAT: file = %s", fname_raw);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			IOStatus ioStatus = iio_stat(fname);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_STAT]++;
			else
				statementsFail[STMT_STAT]++;

			g_free(fname_raw);
			g_free(fname);
			break;
		}

		case STMT_RENAME: {
			ExpressionStatus status[2];
			ParameterList* paramList = stmt->parameters;
			gchar* oldname_raw = param_string_get(paramList, 0, &status[0]);
			gchar* newname_raw = param_string_get(paramList, 1, &status[1]);

			Verbose("~ Executing STMT_RENAME: oldname = %s, newname = %s", oldname_raw, oldname_raw);

			// evaluator error check
			if (!expr_status_assert(status, 2)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* oldname = var_replace_substrings(oldname_raw);
			gchar* newname = var_replace_substrings(newname_raw);

			IOStatus ioStatus = iio_rename(oldname, newname);
			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_RENAME]++;
			else
				statementsFail[STMT_RENAME]++;

			g_free(oldname_raw);
			g_free(newname_raw);
			g_free(oldname);
			g_free(newname);
			break;
		}

#ifdef HAVE_MPI
		case STMT_PFOPEN: {
			ExpressionStatus status[3];
			ParameterList* paramList = stmt->parameters;
			gchar* fhname = param_string_get(paramList, 0, &status[0]);
			gchar* fname_raw = param_string_get(paramList, 1, &status[1]);
			gchar* mode = param_string_get(paramList, 2, &status[2]);

			Verbose("~ Executing STMT_FOPEN: fhname = %s, fname = %s mode = %s", fhname, fname_raw, mode);

			// evaluator error check
			if (!expr_status_assert(status, 3)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);
			MPI_Comm comm = MPI_COMM_WORLD;
			if(groupStack)
				comm = ((GroupBlock*) g_list_first(groupStack)->data)->mpicomm;

			File* file;
			if (iio_pfopen(fname, mode, comm, &file)) {
				Verbose("  > file = %p", file);
				var_set_value(fhname, VAR_FILE, &file);
				statementsSucceed[STMT_PFOPEN]++;
			}
			else
				statementsFail[STMT_PFOPEN]++;

			g_free(fhname);
			g_free(fname_raw);
			g_free(fname);
			g_free(mode);
			break;
		}

		case STMT_PFCLOSE: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			File* file = param_file_get(paramList, 0, &status[0]);

			Verbose("~ Executing STMT_FCLOSE: file = %p", file);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			if (file && iio_pfclose(file)) {
				gchar* fhname = (gchar*) param_value_get(paramList, 0);
				var_destroy(fhname);
				statementsSucceed[STMT_PFCLOSE]++;
			}
			else
				statementsFail[STMT_PFCLOSE]++;
			break;
		}

		case STMT_PFWRITE: {
			ExpressionStatus status[2];
			ParameterList* paramList = stmt->parameters;
			File*  file = param_file_get(paramList, 0, &status[0]);
			gchar* pname = param_string_get(paramList, 1, &status[1]);

			Verbose("~ Executing STMT_PFWRITE: file = %p, pattern = %s", file, pname);

			// evaluator error check
			if (!expr_status_assert(status, 2)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			Pattern* pattern = g_hash_table_lookup(patternMap, pname);
			if (!pattern) {
				g_printf("Invalid pattern parameter in statement pfwrite.\n");
				Error("Malicious statement parameters!");
				break;
			}

			MPI_Comm comm = MPI_COMM_WORLD;
			if(groupStack)
				comm = ((GroupBlock*) g_list_first(groupStack)->data)->mpicomm;

			IOStatus ioStatus;
			switch(pattern->level) {
				/* Level 0: non-collective, contiguous */
				case 0:
					Verbose("  > level = 0");
					ioStatus = iio_pfwrite_level0(file, pattern);
					break;

				/* Level 1: collective, contiguous */
				case 1:
					Verbose("  > level = 1");
					ioStatus = iio_pfwrite_level1(file, pattern);
					break;

				/* Level 2: non-collective, non-contiguous */
				case 2:
					Verbose("  > level = 2");
					ioStatus = iio_pfwrite_level2(file, pattern);
					break;

				/* Level 3: collective, non-contiguous */
				case 3:
					Verbose("  > level = 3");
					ioStatus = iio_pfwrite_level3(file, pattern);
					break;

				default: Error("Invalid level (%d) for statement pfwrite!", pattern->level);
			}

			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_PFWRITE]++;
			else
				statementsFail[STMT_PFWRITE]++;

			g_free(pname);
			break;
		}

		case STMT_PFREAD: {
			ExpressionStatus status[2];
			ParameterList* paramList = stmt->parameters;
			File*  file = param_file_get(paramList, 0, &status[0]);
			gchar* pname = param_string_get(paramList, 1, &status[1]);

			Verbose("~ Executing STMT_PFREAD: file = %p, pattern = %s", file, pname);

			// evaluator error check
			if (!expr_status_assert(status, 2)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			Pattern* pattern = g_hash_table_lookup(patternMap, pname);
			if (!pattern) {
				g_printf("Invalid pattern parameter in statement pread.\n");
				Error("Malicious statement parameters!");
				break;
			}

			MPI_Comm comm = MPI_COMM_WORLD;
			if(groupStack)
				comm = ((GroupBlock*) g_list_first(groupStack)->data)->mpicomm;

			IOStatus ioStatus;
			switch(pattern->level) {
				/* Level 0: non-collective, contiguous */
				case 0:
					Verbose("  > level = 0");
					ioStatus = iio_pfread_level0(file, pattern);
					break;

				/* Level 1: collective, contiguous */
				case 1:
					Verbose("  > level = 1");
					ioStatus = iio_pfread_level1(file, pattern);
					break;

				/* Level 2: non-collective, non-contiguous */
				case 2:
					Verbose("  > level = 2");
					ioStatus = iio_pfread_level2(file, pattern);
					break;

				/* Level 3: collective, non-contiguous */
				case 3:
					Verbose("  > level = 3");
					ioStatus = iio_pfread_level3(file, pattern);
					break;

				default: Error("Invalid level (%d) for statement pfread!", pattern->level);
			}

			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_PFREAD]++;
			else
				statementsFail[STMT_PFREAD]++;

			g_free(pname);
			break;
		}

		case STMT_PWRITE: {
			ExpressionStatus status[2];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);
			gchar* pname = param_string_get(paramList, 1, &status[1]);

			Verbose("~ Executing STMT_PWRITE: file = %s, pattern = %s", fname_raw, pname);

			// evaluator error check
			if (!expr_status_assert(status, 2)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			Pattern* pattern = g_hash_table_lookup(patternMap, pname);
			if (!pattern) {
				g_printf("Invalid pattern parameter in statement pwrite.\n");
				Error("Malicious statement parameters!");
				break;
			}

			MPI_Comm comm = MPI_COMM_WORLD;
			if(groupStack)
				comm = ((GroupBlock*) g_list_first(groupStack)->data)->mpicomm;

			IOStatus ioStatus;
			switch(pattern->level) {
				/* Level 0: non-collective, contiguous */
				case 0:
					Verbose("  > level = 0");
					ioStatus = iio_pwrite_level0(fname, pattern, comm);
					break;

				/* Level 1: collective, contiguous */
				case 1:
					Verbose("  > level = 1");
					ioStatus = iio_pwrite_level1(fname, pattern, comm);
					break;

				/* Level 2: non-collective, non-contiguous */
				case 2:
					Verbose("  > level = 2");
					ioStatus = iio_pwrite_level2(fname, pattern, comm);
					break;

				/* Level 3: collective, non-contiguous */
				case 3:
					Verbose("  > level = 3");
					ioStatus = iio_pwrite_level3(fname, pattern, comm);
					break;

				default: Error("Invalid level (%d) for statement pwrite!", pattern->level);
			}

			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_PWRITE]++;
			else
				statementsFail[STMT_PWRITE]++;

			g_free(fname_raw);
			g_free(fname);
			g_free(pname);
			break;
		}

		case STMT_PREAD: {
			ExpressionStatus status[2];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);
			gchar* pname = param_string_get(paramList, 1, &status[1]);

			Verbose("~ Executing STMT_PREAD: file = %s, pattern = %s", fname_raw, pname);

			// evaluator error check
			if (!expr_status_assert(status, 2)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			Pattern* pattern = g_hash_table_lookup(patternMap, pname);
			if (!pattern) {
				g_printf("Invalid pattern parameter in statement pread.\n");
				g_free(fname);
				Error("Malicious statement parameters!");
				break;
			}

			MPI_Comm comm = MPI_COMM_WORLD;
			if(groupStack)
				comm = ((GroupBlock*) g_list_first(groupStack)->data)->mpicomm;

			IOStatus ioStatus;
			switch(pattern->level) {
				/* Level 0: non-collective, contiguous */
				case 0:
					Verbose("  > level = 0");
					ioStatus = iio_pread_level0(fname, pattern, comm);
					break;

				/* Level 1: collective, contiguous */
				case 1:
					Verbose("  > level = 1");
					ioStatus = iio_pread_level1(fname, pattern, comm);
					break;

				/* Level 2: non-collective, non-contiguous */
				case 2:
					Verbose("  > level = 2");
					ioStatus = iio_pread_level2(fname, pattern, comm);
					break;

				/* Level 3: collective, non-contiguous */
				case 3:
					Verbose("  > level = 3");
					ioStatus = iio_pread_level3(fname, pattern, comm);
					break;

				default: Error("Invalid level (%d) for statement pread!", pattern->level);
			}

			dump_coretime(coreTimeStack, ioStatus.coreTime);

			if (ioStatus.success)
				statementsSucceed[STMT_PREAD]++;
			else
				statementsFail[STMT_PREAD]++;

			g_free(fname_raw);
			g_free(fname);
			g_free(pname);
			break;
		}

		case STMT_PDELETE: {
			ExpressionStatus status[1];
			ParameterList* paramList = stmt->parameters;
			gchar* fname_raw = param_string_get(paramList, 0, &status[0]);

			Verbose("~ Executing STMT_PDELETE: file = %s", fname_raw);

			// evaluator error check
			if (!expr_status_assert(status, 1)) {
				backtrace(stmt);
				Error("Malicious statement parameters!");
			}

			gchar* fname = var_replace_substrings(fname_raw);

			if (iio_pdelete(fname))
				statementsSucceed[STMT_PDELETE]++;
			else
				statementsFail[STMT_PDELETE]++;

			g_free(fname_raw);
			g_free(fname);
			break;
		}
#endif

		/* ![ModuleHook] statement_exec */

		default: Error("Invalid statement! (id=%d)\n", stmt->type);
	}
}