init: HW1

This commit is contained in:
ytshih committed 2026-10-05 04:41:24 +08:00
commit bf65e37202
20 files changed
+1197

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
CXX := g++
CXXFLAGS := -O3 -std=c++17 -Wall
ifneq ($(VECTOR_WIDTH),)
CXXFLAGS += -DVECTOR_WIDTH=$(VECTOR_WIDTH)
endif
all: myexp
logger.o: logger.cpp logger.h PPintrin.h PPintrin.cpp def.h
$(CXX) $(CXXFLAGS) -c logger.cpp
PPintrin.o: PPintrin.cpp PPintrin.h logger.cpp logger.h def.h
$(CXX) $(CXXFLAGS) -c PPintrin.cpp
myexp: PPintrin.o logger.o main.cpp serialOP.cpp vectorOP.cpp
$(CXX) $(CXXFLAGS) logger.o PPintrin.o main.cpp serialOP.cpp vectorOP.cpp -o myexp
clean:
$(RM) *.o *.s myexp *~
+304
View File
@@ -0,0 +1,304 @@
#include "PPintrin.h"
#include "logger.h"
//******************
//* Implementation *
//******************
__pp_mask _pp_init_ones(int first)
{
__pp_mask mask;
for (int i = 0; i < VECTOR_WIDTH; i++)
{
mask.value[i] = (i < first) ? true : false;
}
return mask;
}
__pp_mask _pp_mask_not(__pp_mask &maska)
{
__pp_mask resultMask;
for (int i = 0; i < VECTOR_WIDTH; i++)
{
resultMask.value[i] = !maska.value[i];
}
PPLogger.addLog("masknot", _pp_init_ones(), VECTOR_WIDTH);
return resultMask;
}
__pp_mask _pp_mask_or(__pp_mask &maska, __pp_mask &maskb)
{
__pp_mask resultMask;
for (int i = 0; i < VECTOR_WIDTH; i++)
{
resultMask.value[i] = maska.value[i] | maskb.value[i];
}
PPLogger.addLog("maskor", _pp_init_ones(), VECTOR_WIDTH);
return resultMask;
}
__pp_mask _pp_mask_and(__pp_mask &maska, __pp_mask &maskb)
{
__pp_mask resultMask;
for (int i = 0; i < VECTOR_WIDTH; i++)
{
resultMask.value[i] = maska.value[i] && maskb.value[i];
}
PPLogger.addLog("maskand", _pp_init_ones(), VECTOR_WIDTH);
return resultMask;
}
int _pp_cntbits(__pp_mask &maska)
{
int count = 0;
for (int i = 0; i < VECTOR_WIDTH; i++)
{
if (maska.value[i])
count++;
}
PPLogger.addLog("cntbits", _pp_init_ones(), VECTOR_WIDTH);
return count;
}
template <typename T>
void _pp_vset(__pp_vec<T> &vecResult, T value, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
vecResult.value[i] = mask.value[i] ? value : vecResult.value[i];
}
PPLogger.addLog("vset", mask, VECTOR_WIDTH);
}
template void _pp_vset<float>(__pp_vec_float &vecResult, float value, __pp_mask &mask);
template void _pp_vset<int>(__pp_vec_int &vecResult, int value, __pp_mask &mask);
void _pp_vset_float(__pp_vec_float &vecResult, float value, __pp_mask &mask) { _pp_vset<float>(vecResult, value, mask); }
void _pp_vset_int(__pp_vec_int &vecResult, int value, __pp_mask &mask) { _pp_vset<int>(vecResult, value, mask); }
__pp_vec_float _pp_vset_float(float value)
{
__pp_vec_float vecResult;
__pp_mask mask = _pp_init_ones();
_pp_vset_float(vecResult, value, mask);
return vecResult;
}
__pp_vec_int _pp_vset_int(int value)
{
__pp_vec_int vecResult;
__pp_mask mask = _pp_init_ones();
_pp_vset_int(vecResult, value, mask);
return vecResult;
}
template <typename T>
void _pp_vmove(__pp_vec<T> &dest, __pp_vec<T> &src, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
dest.value[i] = mask.value[i] ? src.value[i] : dest.value[i];
}
PPLogger.addLog("vmove", mask, VECTOR_WIDTH);
}
template void _pp_vmove<float>(__pp_vec_float &dest, __pp_vec_float &src, __pp_mask &mask);
template void _pp_vmove<int>(__pp_vec_int &dest, __pp_vec_int &src, __pp_mask &mask);
void _pp_vmove_float(__pp_vec_float &dest, __pp_vec_float &src, __pp_mask &mask) { _pp_vmove<float>(dest, src, mask); }
void _pp_vmove_int(__pp_vec_int &dest, __pp_vec_int &src, __pp_mask &mask) { _pp_vmove<int>(dest, src, mask); }
template <typename T>
void _pp_vload(__pp_vec<T> &dest, T *src, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
dest.value[i] = mask.value[i] ? src[i] : dest.value[i];
}
PPLogger.addLog("vload", mask, VECTOR_WIDTH);
}
template void _pp_vload<float>(__pp_vec_float &dest, float *src, __pp_mask &mask);
template void _pp_vload<int>(__pp_vec_int &dest, int *src, __pp_mask &mask);
void _pp_vload_float(__pp_vec_float &dest, float *src, __pp_mask &mask) { _pp_vload<float>(dest, src, mask); }
void _pp_vload_int(__pp_vec_int &dest, int *src, __pp_mask &mask) { _pp_vload<int>(dest, src, mask); }
template <typename T>
void _pp_vstore(T *dest, __pp_vec<T> &src, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
dest[i] = mask.value[i] ? src.value[i] : dest[i];
}
PPLogger.addLog("vstore", mask, VECTOR_WIDTH);
}
template void _pp_vstore<float>(float *dest, __pp_vec_float &src, __pp_mask &mask);
template void _pp_vstore<int>(int *dest, __pp_vec_int &src, __pp_mask &mask);
void _pp_vstore_float(float *dest, __pp_vec_float &src, __pp_mask &mask) { _pp_vstore<float>(dest, src, mask); }
void _pp_vstore_int(int *dest, __pp_vec_int &src, __pp_mask &mask) { _pp_vstore<int>(dest, src, mask); }
template <typename T>
void _pp_vadd(__pp_vec<T> &vecResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
vecResult.value[i] = mask.value[i] ? (veca.value[i] + vecb.value[i]) : vecResult.value[i];
}
PPLogger.addLog("vadd", mask, VECTOR_WIDTH);
}
template void _pp_vadd<float>(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
template void _pp_vadd<int>(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
void _pp_vadd_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vadd<float>(vecResult, veca, vecb, mask); }
void _pp_vadd_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vadd<int>(vecResult, veca, vecb, mask); }
template <typename T>
void _pp_vsub(__pp_vec<T> &vecResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
vecResult.value[i] = mask.value[i] ? (veca.value[i] - vecb.value[i]) : vecResult.value[i];
}
PPLogger.addLog("vsub", mask, VECTOR_WIDTH);
}
template void _pp_vsub<float>(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
template void _pp_vsub<int>(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
void _pp_vsub_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vsub<float>(vecResult, veca, vecb, mask); }
void _pp_vsub_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vsub<int>(vecResult, veca, vecb, mask); }
template <typename T>
void _pp_vmult(__pp_vec<T> &vecResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
vecResult.value[i] = mask.value[i] ? (veca.value[i] * vecb.value[i]) : vecResult.value[i];
}
PPLogger.addLog("vmult", mask, VECTOR_WIDTH);
}
template void _pp_vmult<float>(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
template void _pp_vmult<int>(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
void _pp_vmult_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vmult<float>(vecResult, veca, vecb, mask); }
void _pp_vmult_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vmult<int>(vecResult, veca, vecb, mask); }
template <typename T>
void _pp_vdiv(__pp_vec<T> &vecResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
vecResult.value[i] = mask.value[i] ? (veca.value[i] / vecb.value[i]) : vecResult.value[i];
}
PPLogger.addLog("vdiv", mask, VECTOR_WIDTH);
}
template void _pp_vdiv<float>(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
template void _pp_vdiv<int>(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
void _pp_vdiv_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vdiv<float>(vecResult, veca, vecb, mask); }
void _pp_vdiv_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vdiv<int>(vecResult, veca, vecb, mask); }
template <typename T>
void _pp_vabs(__pp_vec<T> &vecResult, __pp_vec<T> &veca, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
vecResult.value[i] = mask.value[i] ? (abs(veca.value[i])) : vecResult.value[i];
}
PPLogger.addLog("vabs", mask, VECTOR_WIDTH);
}
template void _pp_vabs<float>(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_mask &mask);
template void _pp_vabs<int>(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_mask &mask);
void _pp_vabs_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_mask &mask) { _pp_vabs<float>(vecResult, veca, mask); }
void _pp_vabs_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_mask &mask) { _pp_vabs<int>(vecResult, veca, mask); }
template <typename T>
void _pp_vgt(__pp_mask &maskResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
maskResult.value[i] = mask.value[i] ? (veca.value[i] > vecb.value[i]) : maskResult.value[i];
}
PPLogger.addLog("vgt", mask, VECTOR_WIDTH);
}
template void _pp_vgt<float>(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
template void _pp_vgt<int>(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
void _pp_vgt_float(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vgt<float>(maskResult, veca, vecb, mask); }
void _pp_vgt_int(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vgt<int>(maskResult, veca, vecb, mask); }
template <typename T>
void _pp_vlt(__pp_mask &maskResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
maskResult.value[i] = mask.value[i] ? (veca.value[i] < vecb.value[i]) : maskResult.value[i];
}
PPLogger.addLog("vlt", mask, VECTOR_WIDTH);
}
template void _pp_vlt<float>(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
template void _pp_vlt<int>(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
void _pp_vlt_float(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vlt<float>(maskResult, veca, vecb, mask); }
void _pp_vlt_int(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vlt<int>(maskResult, veca, vecb, mask); }
template <typename T>
void _pp_veq(__pp_mask &maskResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
maskResult.value[i] = mask.value[i] ? (veca.value[i] == vecb.value[i]) : maskResult.value[i];
}
PPLogger.addLog("veq", mask, VECTOR_WIDTH);
}
template void _pp_veq<float>(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
template void _pp_veq<int>(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
void _pp_veq_float(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_veq<float>(maskResult, veca, vecb, mask); }
void _pp_veq_int(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_veq<int>(maskResult, veca, vecb, mask); }
template <typename T>
void _pp_hadd(__pp_vec<T> &vecResult, __pp_vec<T> &vec)
{
for (int i = 0; i < VECTOR_WIDTH / 2; i++)
{
T result = vec.value[2 * i] + vec.value[2 * i + 1];
vecResult.value[2 * i] = result;
vecResult.value[2 * i + 1] = result;
}
PPLogger.addLog("hadd", _pp_init_ones(), VECTOR_WIDTH);
}
template void _pp_hadd<float>(__pp_vec_float &vecResult, __pp_vec_float &vec);
void _pp_hadd_float(__pp_vec_float &vecResult, __pp_vec_float &vec) { _pp_hadd<float>(vecResult, vec); }
template <typename T>
void _pp_interleave(__pp_vec<T> &vecResult, __pp_vec<T> vec)
{
for (int i = 0; i < VECTOR_WIDTH; i++)
{
int index = i < VECTOR_WIDTH / 2 ? (2 * i) : (2 * (i - VECTOR_WIDTH / 2) + 1);
vecResult.value[i] = vec.value[index];
}
PPLogger.addLog("interleave", _pp_init_ones(), VECTOR_WIDTH);
}
template void _pp_interleave<float>(__pp_vec_float &vecResult, __pp_vec_float vec);
void _pp_interleave_float(__pp_vec_float &vecResult, __pp_vec_float vec) { _pp_interleave<float>(vecResult, vec); }
void addUserLog(const char *logStr)
{
PPLogger.addLog(logStr, _pp_init_ones(), 0);
}
+123
View File
@@ -0,0 +1,123 @@
#ifndef PPINTRIN_H_
#define PPINTRIN_H_
#include <cstdlib>
#include <cmath>
#include "logger.h"
#include "def.h"
//*******************
//* Type Definition *
//*******************
extern Logger PPLogger;
template <typename T>
struct __pp_vec {
T value[VECTOR_WIDTH];
};
// Declare a mask with __pp_mask
struct __pp_mask : __pp_vec<bool> {};
// Declare a floating point vector register with __pp_vec_float
#define __pp_vec_float __pp_vec<float>
// Declare an integer vector register with __pp_vec_int
#define __pp_vec_int __pp_vec<int>
//***********************
//* Function Definition *
//***********************
// Return a mask initialized to 1 in the first N lanes and 0 in the others
__pp_mask _pp_init_ones(int first = VECTOR_WIDTH);
// Return the inverse of maska
__pp_mask _pp_mask_not(__pp_mask &maska);
// Return (maska | maskb)
__pp_mask _pp_mask_or(__pp_mask &maska, __pp_mask &maskb);
// Return (maska & maskb)
__pp_mask _pp_mask_and(__pp_mask &maska, __pp_mask &maskb);
// Count the number of 1s in maska
int _pp_cntbits(__pp_mask &maska);
// Set register to value if vector lane is active
// otherwise keep the old value
void _pp_vset_float(__pp_vec_float &vecResult, float value, __pp_mask &mask);
void _pp_vset_int(__pp_vec_int &vecResult, int value, __pp_mask &mask);
// For user's convenience, returns a vector register with all lanes initialized to value
__pp_vec_float _pp_vset_float(float value);
__pp_vec_int _pp_vset_int(int value);
// Copy values from vector register src to vector register dest if vector lane active
// otherwise keep the old value
void _pp_vmove_float(__pp_vec_float &dest, __pp_vec_float &src, __pp_mask &mask);
void _pp_vmove_int(__pp_vec_int &dest, __pp_vec_int &src, __pp_mask &mask);
// Load values from array src to vector register dest if vector lane active
// otherwise keep the old value
void _pp_vload_float(__pp_vec_float &dest, float* src, __pp_mask &mask);
void _pp_vload_int(__pp_vec_int &dest, int* src, __pp_mask &mask);
// Store values from vector register src to array dest if vector lane active
// otherwise keep the old value
void _pp_vstore_float(float* dest, __pp_vec_float &src, __pp_mask &mask);
void _pp_vstore_int(int* dest, __pp_vec_int &src, __pp_mask &mask);
// Return calculation of (veca + vecb) if vector lane active
// otherwise keep the old value
void _pp_vadd_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
void _pp_vadd_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
// Return calculation of (veca - vecb) if vector lane active
// otherwise keep the old value
void _pp_vsub_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
void _pp_vsub_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
// Return calculation of (veca * vecb) if vector lane active
// otherwise keep the old value
void _pp_vmult_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
void _pp_vmult_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
// Return calculation of (veca / vecb) if vector lane active
// otherwise keep the old value
void _pp_vdiv_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
void _pp_vdiv_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
// Return calculation of absolute value abs(veca) if vector lane active
// otherwise keep the old value
void _pp_vabs_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_mask &mask);
void _pp_vabs_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_mask &mask);
// Return a mask of (veca > vecb) if vector lane active
// otherwise keep the old value
void _pp_vgt_float(__pp_mask &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
void _pp_vgt_int(__pp_mask &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
// Return a mask of (veca < vecb) if vector lane active
// otherwise keep the old value
void _pp_vlt_float(__pp_mask &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
void _pp_vlt_int(__pp_mask &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
// Return a mask of (veca == vecb) if vector lane active
// otherwise keep the old value
void _pp_veq_float(__pp_mask &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
void _pp_veq_int(__pp_mask &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
// Adds up adjacent pairs of elements, so
// [0 1 2 3] -> [0+1 0+1 2+3 2+3]
void _pp_hadd_float(__pp_vec_float &vecResult, __pp_vec_float &vec);
// Performs an even-odd interleaving where all even-indexed elements move to front half
// of the array and odd-indexed to the back half, so
// [0 1 2 3 4 5 6 7] -> [0 2 4 6 1 3 5 7]
void _pp_interleave_float(__pp_vec_float &vecResult, __pp_vec_float vec);
// Add a customized log to help debugging
void addUserLog(const char * logStr);
#endif
BIN
View File
Binary file not shown.
+5
View File
@@ -0,0 +1,5 @@
// Define vector unit width here
#ifndef VECTOR_WIDTH
#define VECTOR_WIDTH 4
#endif
#define EXP_MAX 10
+66
View File
@@ -0,0 +1,66 @@
#include "logger.h"
#include "PPintrin.h"
void Logger::addLog(const char *instruction, __pp_mask mask, int N)
{
Log newLog;
strcpy(newLog.instruction, instruction);
newLog.mask = 0;
for (int i = 0; i < N; i++)
{
if (mask.value[i])
{
newLog.mask |= (((unsigned long long)1) << i);
stats.utilized_lane++;
}
}
stats.total_lane += N;
stats.total_instructions += (N > 0);
log.push_back(newLog);
}
void Logger::printStats()
{
printf("****************** Printing Vector Unit Statistics *******************\n");
printf("Vector Width: %d\n", VECTOR_WIDTH);
printf("Total Vector Instructions: %lld\n", stats.total_instructions);
printf("Vector Utilization: %.1f%%\n", (double)stats.utilized_lane / stats.total_lane * 100);
printf("Utilized Vector Lanes: %lld\n", stats.utilized_lane);
printf("Total Vector Lanes: %lld\n", stats.total_lane);
}
void Logger::printLog()
{
printf("***************** Printing Vector Unit Execution Log *****************\n");
printf(" Instruction | Vector Lane Occupancy ('*' for active, '_' for inactive)\n");
printf("------------- --------------------------------------------------------\n");
for (int i = 0; i < log.size(); i++)
{
printf("%12s | ", log[i].instruction);
for (int j = 0; j < VECTOR_WIDTH; j++)
{
if (log[i].mask & (((unsigned long long)1) << j))
{
printf("*");
}
else
{
printf("_");
}
}
printf("\n");
}
}
void Logger::refresh()
{
stats.total_instructions = 0;
stats.total_lane = 0;
stats.utilized_lane = 0;
fflush(stdout);
};
unsigned long long Logger::getTotalInstrs()
{
return stats.total_instructions;
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef LOGGER_H_
#define LOGGER_H_
#include <stdio.h>
#include <vector>
#include <string.h>
using namespace std;
#define MAX_INST_LEN 32
struct __pp_mask;
struct Log {
char instruction[MAX_INST_LEN];
unsigned long long mask; // support vector width up to 64
};
struct Statistics {
unsigned long long utilized_lane;
unsigned long long total_lane;
unsigned long long total_instructions;
};
class Logger {
private:
vector<Log> log;
Statistics stats;
public:
void addLog(const char * instruction, __pp_mask mask, int N = 0);
void printStats();
void printLog();
void refresh();
unsigned long long getTotalInstrs();
};
#endif
BIN
View File
Binary file not shown.
+204
View File
@@ -0,0 +1,204 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <math.h>
#include "logger.h"
#include <sstream>
#include "def.h"
using namespace std;
Logger PPLogger;
void usage(const char *progname);
void initValue(float *values, int *exponents, float *output, float *gold, unsigned int N);
void absSerial(float *values, float *output, int N);
void absVector(float *values, float *output, int N);
void clampedExpSerial(float *values, int *exponents, float *output, int N);
void clampedExpVector(float *values, int *exponents, float *output, int N);
float arraySumSerial(float *values, int N);
float arraySumVector(float *values, int N);
bool verifyResult(float *values, int *exponents, float *output, float *gold, int N);
int main(int argc, char *argv[])
{
int N = 16;
bool printLog = false;
// parse commandline options ////////////////////////////////////////////
int opt;
static struct option long_options[] = {
{"size", 1, 0, 's'},
{"log", 0, 0, 'l'},
{"help", 0, 0, '?'},
{0, 0, 0, 0}};
while ((opt = getopt_long(argc, argv, "s:l?", long_options, NULL)) != EOF)
{
switch (opt)
{
case 's':
N = atoi(optarg);
if (N <= 0)
{
printf("Error: Workload size is set to %d (<0).\n", N);
return -1;
}
break;
case 'l':
printLog = true;
break;
case '?':
default:
usage(argv[0]);
return 1;
}
}
float *values = new float[N + VECTOR_WIDTH];
int *exponents = new int[N + VECTOR_WIDTH];
float *output = new float[N + VECTOR_WIDTH];
float *gold = new float[N + VECTOR_WIDTH];
initValue(values, exponents, output, gold, N);
clampedExpSerial(values, exponents, gold, N);
clampedExpVector(values, exponents, output, N);
//absSerial(values, gold, N);
//absVector(values, output, N);
printf("\e[1;31mCLAMPED EXPONENT\e[0m (required) \n");
bool clampedCorrect = verifyResult(values, exponents, output, gold, N);
if (printLog)
PPLogger.printLog();
PPLogger.printStats();
printf("************************ Result Verification *************************\n");
if (!clampedCorrect)
{
printf("@@@ ClampedExp Failed!!!\n");
}
else if (PPLogger.getTotalInstrs() == 0)
{
printf("Not using fake intrinsics in ClampedExp\n");
}
else
{
printf("ClampedExp Passed!!!\n");
}
PPLogger.refresh();
printf("\n\e[1;31mARRAY SUM\e[0m (bonus) \n");
if (N % VECTOR_WIDTH == 0)
{
float sumGold = arraySumSerial(values, N);
float sumOutput = arraySumVector(values, N);
if (printLog)
PPLogger.printLog();
PPLogger.printStats();
printf("************************ Result Verification *************************\n");
float epsilon = 0.1;
bool sumCorrect = abs(sumGold - sumOutput) < epsilon * 2;
if (!sumCorrect)
{
printf("Expected %f, got %f\n.", sumGold, sumOutput);
printf("@@@ ArraySum Failed!!!\n");
}
else if (PPLogger.getTotalInstrs() == 0)
{
printf("Not using fake intrinsics in ArraySum\n");
}
else
{
printf("ArraySum Passed!!!\n");
}
}
else
{
printf("Must have N %% VECTOR_WIDTH == 0 for this problem (VECTOR_WIDTH is %d)\n", VECTOR_WIDTH);
}
delete[] values;
delete[] exponents;
delete[] output;
delete[] gold;
return 0;
}
void usage(const char *progname)
{
printf("Usage: %s [options]\n", progname);
printf("Program Options:\n");
printf(" -s --size <N> Use workload size N (Default = 16)\n");
printf(" -l --log Print vector unit execution log\n");
printf(" -? --help This message\n");
}
void initValue(float *values, int *exponents, float *output, float *gold, unsigned int N)
{
for (unsigned int i = 0; i < N + VECTOR_WIDTH; i++)
{
// random input values
values[i] = -1.f + 4.f * static_cast<float>(rand()) / RAND_MAX;
exponents[i] = rand() % EXP_MAX;
output[i] = 0.f;
gold[i] = 0.f;
}
}
bool verifyResult(float *values, int *exponents, float *output, float *gold, int N)
{
int incorrect = -1;
float epsilon = 0.00001;
for (int i = 0; i < N + VECTOR_WIDTH; i++)
{
if (abs(output[i] - gold[i]) > epsilon)
{
incorrect = i;
break;
}
}
if (incorrect != -1)
{
if (incorrect >= N)
printf("You have written to out of bound value!\n");
printf("Wrong calculation at value[%d]!\n", incorrect);
printf("value = ");
for (int i = 0; i < N; i++)
{
printf("% f ", values[i]);
}
printf("\n");
printf("exp = ");
for (int i = 0; i < N; i++)
{
printf("% 9d ", exponents[i]);
}
printf("\n");
printf("output = ");
for (int i = 0; i < N; i++)
{
printf("% f ", output[i]);
}
printf("\n");
printf("gold = ");
for (int i = 0; i < N; i++)
{
printf("% f ", gold[i]);
}
printf("\n");
return false;
}
printf("Results matched with answer!\n");
return true;
}
Executable
BIN
View File
Binary file not shown.
+61
View File
@@ -0,0 +1,61 @@
// computes the absolute value of all elements in the input array
// values, stores result in output
void absSerial(float *values, float *output, int N)
{
for (int i = 0; i < N; i++)
{
float x = values[i];
if (x < 0)
{
output[i] = -x;
}
else
{
output[i] = x;
}
}
}
// accepts an array of values and an array of exponents
//
// For each element, compute values[i]^exponents[i] and clamp value to
// 9.999. Store result in output.
void clampedExpSerial(float *values, int *exponents, float *output, int N)
{
for (int i = 0; i < N; i++)
{
float x = values[i];
int y = exponents[i];
if (y == 0)
{
output[i] = 1.f;
}
else
{
float result = x;
int count = y - 1;
while (count > 0)
{
result *= x;
count--;
}
if (result > 9.999999f)
{
result = 9.999999f;
}
output[i] = result;
}
}
}
// returns the sum of all elements in values
float arraySumSerial(float *values, int N)
{
float sum = 0;
for (int i = 0; i < N; i++)
{
sum += values[i];
}
return sum;
}
+72
View File
@@ -0,0 +1,72 @@
#include "PPintrin.h"
// implementation of absSerial(), but it is vectorized using PP intrinsics
void absVector(float *values, float *output, int N)
{
__pp_vec_float x;
__pp_vec_float result;
__pp_vec_float zero = _pp_vset_float(0.f);
__pp_mask maskAll, maskIsNegative, maskIsNotNegative;
// Note: Take a careful look at this loop indexing. This example
// code is not guaranteed to work when (N % VECTOR_WIDTH) != 0.
// Why is that the case?
for (int i = 0; i < N; i += VECTOR_WIDTH)
{
// All ones
maskAll = _pp_init_ones();
// All zeros
maskIsNegative = _pp_init_ones(0);
// Load vector of values from contiguous memory addresses
_pp_vload_float(x, values + i, maskAll); // x = values[i];
// Set mask according to predicate
_pp_vlt_float(maskIsNegative, x, zero, maskAll); // if (x < 0) {
// Execute instruction using mask ("if" clause)
_pp_vsub_float(result, zero, x, maskIsNegative); // output[i] = -x;
// Inverse maskIsNegative to generate "else" mask
maskIsNotNegative = _pp_mask_not(maskIsNegative); // } else {
// Execute instruction ("else" clause)
_pp_vload_float(result, values + i, maskIsNotNegative); // output[i] = x; }
// Write results back to memory
_pp_vstore_float(output + i, result, maskAll);
}
}
void clampedExpVector(float *values, int *exponents, float *output, int N)
{
//
// PP STUDENTS TODO: Implement your vectorized version of
// clampedExpSerial() here.
//
// Your solution should work for any value of
// N and VECTOR_WIDTH, not just when VECTOR_WIDTH divides N
//
for (int i = 0; i < N; i += VECTOR_WIDTH)
{
}
}
// returns the sum of all elements in values
// You can assume N is a multiple of VECTOR_WIDTH
// You can assume VECTOR_WIDTH is a power of 2
float arraySumVector(float *values, int N)
{
//
// PP STUDENTS TODO: Implement your vectorized version of arraySumSerial here
//
for (int i = 0; i < N; i += VECTOR_WIDTH)
{
}
return 0.0;
}
+53
View File
@@ -0,0 +1,53 @@
TARGET := test_auto_vectorize
OBJS := main.o test1.o test2.o test3.o
CC := clang
CFLAGS := -O3 -std=c11 -Wall -D_POSIX_C_SOURCE=200809L
ifeq ($(ASSEMBLE),1)
CFLAGS += -S
endif
ifeq ($(VECTORIZE),1)
CFLAGS += -Rpass=loop-vectorize -Rpass-missed=loop-vectorize -Rpass-analysis=loop-vectorize
SUFFIX := .vec
else
CFLAGS += -fno-vectorize
SUFFIX := .novec
endif
ifeq ($(RESTRICT),1)
SUFFIX := $(SUFFIX).restr
endif
ifeq ($(ALIGN),1)
SUFFIX := $(SUFFIX).align
endif
ifeq ($(AVX2),1)
CFLAGS += -mavx2
SUFFIX := $(SUFFIX).avx2
endif
ifeq ($(FASTMATH),1)
CFLAGS += -ffast-math
SUFFIX := $(SUFFIX).fmath
endif
all: $(TARGET)
%.o: %.c test.h
ifeq ($(ASSEMBLE),1)
mkdir -p "./assembly"
$(CC) $(CFLAGS) -c $< -o assembly/$(basename $<)$(SUFFIX).s
else
$(CC) $(CFLAGS) -c $<
endif
$(TARGET): $(OBJS)
ifneq ($(ASSEMBLE),1)
$(CC) $(CFLAGS) $(OBJS) -o $@
endif
clean:
$(RM) *.o *.s $(TARGET) *~
cleanall:
$(RM) -r *.o *.s $(TARGET) *~ assembly
+97
View File
@@ -0,0 +1,97 @@
/**
* Copyright (c) 2014 MIT License by 6.172 Staff
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
**/
#ifndef INCLUDED_FASTTIME_DOT_H
#define INCLUDED_FASTTIME_DOT_H
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#ifdef __MACH__
#include <mach/mach_time.h> // mach_absolute_time
typedef uint64_t fasttime_t;
// Return the current time.
static inline fasttime_t gettime(void) {
return mach_absolute_time();
}
// Return the time different between the start and the end, as a float
// in units of seconds. This function does not need to be fast.
// Implementation notes: See
// https://developer.apple.com/library/mac/qa/qa1398/_index.html
static inline double tdiff(fasttime_t start, fasttime_t end) {
static mach_timebase_info_data_t timebase;
int r = mach_timebase_info(&timebase);
assert(r == 0);
fasttime_t elapsed = end-start;
double ns = (double)elapsed * timebase.numer / timebase.denom;
return ns*1e-9;
}
static inline unsigned int random_seed_from_clock(void) {
fasttime_t now = gettime();
return (now & 0xFFFFFFFF) + (now>>32);
}
#else // LINUX
// We need _POSIX_C_SOURCE to pick up 'struct timespec' and clock_gettime.
// #define _POSIX_C_SOURCE 200809L
#include <time.h>
typedef struct timespec fasttime_t;
// Return the current time.
static inline fasttime_t gettime(void) {
struct timespec s;
#ifdef NDEBUG
clock_gettime(CLOCK_MONOTONIC, &s);
#else
int r = clock_gettime(CLOCK_MONOTONIC, &s);
assert(r == 0);
#endif
return s;
}
// Return the time different between the start and the end, as a float
// in units of seconds. This function does not need to be fast.
static inline double tdiff(fasttime_t start, fasttime_t end) {
return end.tv_sec - start.tv_sec + 1e-9*(end.tv_nsec - start.tv_nsec);
}
static inline unsigned int random_seed_from_clock(void) {
fasttime_t now = gettime();
return now.tv_sec + now.tv_nsec;
}
// Poison these symbols to help find portability problems.
int clock_gettime(clockid_t, struct timespec *) __attribute__((deprecated));
time_t time(time_t *) __attribute__((deprecated));
#endif // LINUX
#endif // INCLUDED_FASTTIME_DOT_H
+91
View File
@@ -0,0 +1,91 @@
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include "fasttime.h"
#include "test.h"
void usage(const char *progname);
void initValue(float *values1, float *values2, double *value3, float *output, unsigned int N);
extern void test1(float *a, float *b, float *c, int N);
extern void test2(float *__restrict a, float *__restrict b, float *__restrict c, int N);
extern double test3(double *__restrict a, int N) ;
int main(int argc, char **argv) {
int N = 1024;
int whichTestToRun = 1;
// parse commandline options
int opt;
static struct option long_options[] = {
{"size", 1, 0, 's'},
{"test", 1, 0, 't'},
{"help", 0, 0, '?'},
{0 ,0, 0, 0}
};
while ((opt = getopt_long(argc, argv, "st:?", long_options, NULL)) != EOF) {
switch (opt) {
case 's':
N = atoi(optarg);
if (N <= 0) {
printf("Error: Workload size is set to %d (<0).\n", N);
return -1;
}
break;
case 't':
whichTestToRun = atoi(optarg);
if (whichTestToRun <= 0 || whichTestToRun >= 4) {
printf("Error: test%d() is not available.\n", whichTestToRun);
return -1;
}
break;
case 'h':
default:
usage(argv[0]);
return 1;
}
}
#define AVX_ALIGNMENT 256
float *values1 = (float *)__builtin_alloca_with_align(N * sizeof(float), AVX_ALIGNMENT);
float *values2 = (float *)__builtin_alloca_with_align(N * sizeof(float), AVX_ALIGNMENT);
double *values3 = (double *)__builtin_alloca_with_align(N * sizeof(double), AVX_ALIGNMENT);
float *output = (float *)__builtin_alloca_with_align(N * sizeof(float), AVX_ALIGNMENT);
#undef AVX_ALIGNMENT
initValue(values1, values2, values3, output, N);
printf("Running test%d()...\n", whichTestToRun);
fasttime_t time1 = gettime();
switch (whichTestToRun) {
case 1: test1(values1, values2, output, N); break;
case 2: test2(values1, values2, output, N); break;
case 3: test3(values3, N); break;
}
fasttime_t time2 = gettime();
double elapsedf = tdiff(time1, time2);
printf("Elapsed execution time of the loop in test%d():\n", whichTestToRun);
printf("%lfsec (N: %d, I: %d)\n", elapsedf, N, I);
return 0;
}
void usage(const char *progname) {
printf("Usage: %s [options]\n", progname);
printf("Program Options:\n");
printf(" -s --size <N> Use workload size N (Default = 1024)\n");
printf(" -t --test <N> Just run the testN function (Default = 1)\n");
printf(" -h --help This message\n");
}
void initValue(float *values1, float *values2, double *values3, float *output, unsigned int N) {
for (unsigned int i=0; i<N; i++)
{
// random input values
values1[i] = -1.0f + 4.0f * rand() / (float)RAND_MAX;
values2[i] = -1.0f + 4.0f * rand() / (float)RAND_MAX;
values3[i] = -1.0 + 4.0 * rand() / (double)RAND_MAX;
output[i] = 0.0f;
}
}
+7
View File
@@ -0,0 +1,7 @@
#ifndef TEST_H
#define TEST_H
// Run for multiple experiments to reduce measurement error on gettime().
#define I 20000000
#endif
+11
View File
@@ -0,0 +1,11 @@
#include "test.h"
void test1(float *a, float *b, float *c, int N) {
__builtin_assume(N == 1024);
for (int i=0; i<I; i++) {
for (int j=0; j<N; j++) {
c[j] = a[j] + b[j];
}
}
}
+19
View File
@@ -0,0 +1,19 @@
#include "test.h"
void test2(float *__restrict a, float *__restrict b, float *__restrict c, int N)
{
__builtin_assume(N == 1024);
a = (float *)__builtin_assume_aligned(a, 16);
b = (float *)__builtin_assume_aligned(b, 16);
for (int i = 0; i < I; i++)
{
for (int j = 0; j < N; j++)
{
/* max() */
c[j] = a[j];
if (b[j] > a[j])
c[j] = b[j];
}
}
}
+13
View File
@@ -0,0 +1,13 @@
--- test2.c
+++ test2.c
@@ -14,9 +14,8 @@
for (int j = 0; j < N; j++)
{
/* max() */
- c[j] = a[j];
- if (b[j] > a[j])
- c[j] = b[j];
+ if (b[j] > a[j]) c[j] = b[j];
+ else c[j] = a[j];
}
}
+14
View File
@@ -0,0 +1,14 @@
#include "test.h"
double test3(double *__restrict a, int N) {
__builtin_assume(N == 1024);
a = (double *)__builtin_assume_aligned(a, 16);
double b = 0;
for (int i=0; i<I; i++) {
for (int j=0; j<N; j++) {
b += a[j];
}
}
return b;
}