init: HW1
This commit is contained in:
commit
a6479e729f
19 files changed
+1197
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
// Run for multiple experiments to reduce measurement error on gettime().
|
||||
#define I 20000000
|
||||
|
||||
#endif
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user