init: HW1

This commit is contained in:
ytshih authored and ytshih committed 2026-10-05 06:04:39 +08:00
commit a6479e729f
19 files changed
+1197

No files matched your search

+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;
}