centralized performance resources

This commit is contained in:
Barrett Ruth 2026-01-10 12:21:52 -05:00
commit 50b15a1522
63 changed files with 328466 additions and 0 deletions

View file

@ -0,0 +1,105 @@
# Copyright (c) 2012 MIT License by 6.172 Staff
# List all of your source files here (but not your headers), separated by
# spaces. You'll have to add to this list every time you create a new
# source file.
SRC := testbed.c matrix_multiply.c
# Set the name of your binary. Change it if you like.
PRODUCT := matrix_multiply
################################################################################
# These configuration options change how your code (listed above) is compiled
# every time you type "make". You may have to change these values to complete
# some assignments; you should also feel free to experiment with them.
################################################################################
# This option sets which compiler your code will be compiled with. Likely
# choices are icc, icpc, gcc, g++, clang
CC := clang
# These flags will be applied to your code any time it is built.
CFLAGS := -Wall -std=c99 -D_POSIX_C_SOURCE=200809L -O3
# These flags are applied only if you build your code with "make DEBUG=1". -g
# generates debugging symbols, -DDEBUG defines the preprocessor symbol "DEBUG"
# (so that you can use "#ifdef DEBUG" in your code), and -O0 disables compiler
# optimizations, so that the binary generated more directly corresponds to your
# source code.
CFLAGS_DEBUG := -g -DDEBUG -O0
# In the release version, we ask for many optimizations; -O3 sets the
# optimization level to three. -DNDEBUG defines the NDEBUG macro,
# which disables assertion checks.
CFLAGS_RELEASE := -O1 -DNDEBUG
# These flags are used to invoke Clang's address sanitizer.
CFLAGS_ASAN := -O1 -g -fsanitize=address
# These flags are applied when linking object files together into your binary.
# If you need to link against libraries, add the appropriate flags here. By
# default, your code is linked against the "rt" library with the flag -lrt;
# this library is used by the timing code in the testbed.
LDFLAGS := -lrt -flto -fuse-ld=gold
################################################################################
# You probably won't need to change anything below this line, but if you're
# curious about how makefiles work, or if you'd like to customize the behavior
# of your makefile, go ahead and take a peek.
################################################################################
# You shouldn't need to touch this. This keeps track of whether you are
# building in a release or debug configuration, and sets CFLAGS appropriately.
# (This mechanism is based on one from the original materials for 6.197 by
# Ceryen Tan and Marek Olszewski.)
OLDMODE=$(shell cat .buildmode 2> /dev/null)
ifeq ($(DEBUG),1)
CFLAGS := $(CFLAGS_DEBUG) $(CFLAGS)
ifneq ($(OLDMODE),debug)
$(shell echo debug > .buildmode)
endif
else ifeq ($(ASAN),1)
CFLAGS := $(CFLAGS_ASAN) $(CFLAGS)
LDFLAGS := $(LDFLAGS) -fsanitize=address
ifneq ($(OLDMODE),asan)
$(shell echo asan > .buildmode)
endif
else
CFLAGS := $(CFLAGS_RELEASE) $(CFLAGS)
ifneq ($(OLDMODE),nodebug)
$(shell echo nodebug > .buildmode)
endif
endif
# When you invoke make without an argument, make behaves as though you had
# typed "make all", and builds whatever you have listed here. (It knows to
# pick "make all" because "all" is the first rule listed.)
all: $(PRODUCT)
# This special "target" will remove the binary and all intermediate files.
clean::
rm -f $(OBJ) $(PRODUCT) .buildmode \
$(addsuffix .gcda, $(basename $(SRC))) \
$(addsuffix .gcno, $(basename $(SRC))) \
$(addsuffix .gcov, $(SRC) fasttime.h)
# This rule generates a list of object names. Each of your source files (but
# not your header files) produces a single object file when it's compiled. In
# a later step, all of those object files are linked together to produce the
# binary that you run.
OBJ = $(addsuffix .o, $(basename $(SRC)))
# These rules tell make how to automatically generate rules that build the
# appropriate object-file from each of the source files listed in SRC (above).
%.o : %.c .buildmode
$(CC) $(CFLAGS) -c $< -o $@
%.o : %.cc .buildmode
$(CC) $(CFLAGS) -c $< -o $@
%.o : %.cpp .buildmode
$(CC) $(CFLAGS) -c $< -o $@
# This rule tells make that it can produce your binary by linking together all
# of the object files produced from your source files and any necessary
# libraries.
$(PRODUCT): $(OBJ) .buildmode
$(CC) -o $@ $(OBJ) $(LDFLAGS)

View file

@ -0,0 +1,95 @@
/**
* 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
#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

View file

@ -0,0 +1,96 @@
/**
* Copyright (c) 2012 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.
**/
#include "./matrix_multiply.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <math.h>
#include <string.h>
// #include "./tbassert.h"
// Allocates a row-by-cols matrix and returns it
matrix* make_matrix(int rows, int cols) {
matrix* new_matrix = malloc(sizeof(matrix));
// Set the number of rows and columns
new_matrix->rows = rows;
new_matrix->cols = cols;
// Allocate a buffer big enough to hold the matrix.
new_matrix->values = (int**)malloc(sizeof(int*) * rows);
for (int i = 0; i < rows; i++) {
new_matrix->values[i] = (int*)malloc(sizeof(int) * cols);
}
return new_matrix;
}
// Frees an allocated matrix
void free_matrix(matrix* m) {
for (int i = 0; i < m->rows; i++) {
free(m->values[i]);
}
free(m->values);
free(m);
}
// Print matrix
void print_matrix(const matrix* m) {
printf("------------\n");
for (int i = 0; i < m->rows; i++) {
for (int j = 0; j < m->cols; j++) {
printf(" %3d ", m->values[i][j]);
}
printf("\n");
}
printf("------------\n");
}
// Multiply matrix A*B, store result in C.
int matrix_multiply_run(const matrix* A, const matrix* B, matrix* C) {
/*
tbassert(A->cols == B->rows,
"A->cols = %d, B->rows = %d\n", A->cols, B->rows);
tbassert(A->rows == C->rows,
"A->rows = %d, C->rows = %d\n", A->rows, C->rows);
tbassert(B->cols == C->cols,
"B->cols = %d, C->cols = %d\n", B->cols, C->cols);
*/
for (int i = 0; i < A->rows; i++) {
for (int j = 0; j < B->cols; j++) {
for (int k = 0; k < A->cols; k++) {
C->values[i][j] += A->values[i][k] * B->values[k][j];
}
}
}
return 0;
}

View file

@ -0,0 +1,58 @@
/**
* Copyright (c) 2012 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.
**/
/**
* Matrix Multiply
*
*
* Declarations here are your API specification -- we expect that your
* code defines and correctly implements these functions and does not modify
* the way the reference implementation uses variables mentioned here,
* so that we may call them from testbed.c and any other testing software
* that we write!
*
* Deviating from this API may cause your program to fail all of our tests.
**/
#ifndef MATRIX_MULTIPLY_H_INCLUDED
#define MATRIX_MULTIPLY_H_INCLUDED
typedef struct {
int rows;
int cols;
int** values;
} matrix;
// Multiply matrix A*B, store result in C.
int matrix_multiply_run(const matrix* A, const matrix* B, matrix* C);
// Allocates a row-by-cols matrix and returns it
matrix* make_matrix(int rows, int cols);
// Frees an allocated matrix
void free_matrix(matrix* m);
// Print matrix
void print_matrix(const matrix* m);
#endif // MATRIX_MULTIPLY_H_INCLUDED

View file

@ -0,0 +1,73 @@
/**
* Copyright (c) 2014 MIT License by Tao B. Schardl
*
* 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 _TBASSERT_H_
#define _TBASSERT_H_ 1
#ifndef NDEBUG
/**************************************************************************
* Library of debugging macros.
*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
// Print a message to STREAM when DEBUG = 1. This macro takes the
// same arguments as FPRINTF().
#define DEBUG_FPRINTF(STREAM, ...) \
do { \
fprintf(STREAM, "%s:%d (%s) ", \
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
fprintf(STREAM, __VA_ARGS__); \
} while (0)
// Print a message to STDERR when DEBUG = 1. This macro takes the
// same arguments as PRINTF().
#define DEBUG_EPRINTF(...) DEBUG_FPRINTF(stderr, __VA_ARGS__);
// If PREDICATE is true, do nothing. Otherwise, print an error with
// the specified message to STDERR. This macro only operates when
// DEBUG = 1. This macro takes a PREDICATE to evaluate followed by
// the standard arguments to PRINTF().
#define DEBUG_ASSERT(PREDICATE, ...) \
do { \
if (!(PREDICATE)) { \
fprintf(stderr, "%s:%d (%s) Assertion " #PREDICATE " failed: ", \
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
fprintf(stderr, __VA_ARGS__); \
abort(); \
} \
} while (0)
#define tbassert DEBUG_ASSERT
#else
#define DEBUG_PRINTF(...) // Nothing.
#define DEBUG_EPRINTF(...) // Nothing.
#define DEBUG_ASSERT(...) // Nothing.
#define tbassert(...) // Nothing.
#endif
#endif // _TBASSERT_H_

View file

@ -0,0 +1,154 @@
/**
* Copyright (c) 2012 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.
**/
/**
* testbed.c:
*
* This file runs your code, timing its execution and printing out the result.
**/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "./fasttime.h"
#include "./matrix_multiply.h"
int main(int argc, char** argv) {
int optchar = 0;
int show_usec = 0;
int should_print = 0;
int use_zero_matrix = 0;
// Always use the same seed, so that our tests are repeatable.
unsigned int randomSeed = 1;
matrix* A;
matrix* B;
matrix* C;
const int kMatrixSize = 4;
// Parse command line arguments
while ((optchar = getopt(argc, argv, "upz")) != -1) {
switch (optchar) {
case 'u':
show_usec = 1;
break;
case 'p':
should_print = 1;
break;
case 'z':
use_zero_matrix = 1;
break;
default:
printf("Ignoring unrecognized option: %c\n", optchar);
continue;
}
}
// This is a trick to make the memory bug leads to a wrong output.
int size = sizeof(int) * 4;
int* temp[20];
for (int i = 0; i < 20; i++) {
temp[i] = (int*)malloc(size);
memset(temp[i], 1, size);
}
int total = 0;
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 4; j++) {
total += temp[i][j];
}
}
if (!total) printf("Trick to stop mallocs from being optimized out.");
for (int i = 0; i < 20; i++) {
free(temp[i]);
}
fprintf(stderr, "Setup\n");
A = make_matrix(kMatrixSize, kMatrixSize+1);
B = make_matrix(kMatrixSize, kMatrixSize);
C = make_matrix(kMatrixSize, kMatrixSize);
if (use_zero_matrix) {
for (int i = 0; i < A->rows; i++) {
for (int j = 0; j < A->cols; j++) {
A->values[i][j] = 0;
}
}
for (int i = 0; i < B->rows; i++) {
for (int j = 0; j < B->cols; j++) {
B->values[i][j] = 0;
}
}
} else {
for (int i = 0; i < A->rows; i++) {
for (int j = 0; j < A->cols; j++) {
A->values[i][j] = rand_r(&randomSeed) % 10;
}
}
for (int i = 0; i < B->rows; i++) {
for (int j = 0; j < B->cols; j++) {
B->values[i][j] = rand_r(&randomSeed) % 10;
}
}
}
if (should_print) {
printf("Matrix A: \n");
print_matrix(A);
printf("Matrix B: \n");
print_matrix(B);
}
fprintf(stderr, "Running matrix_multiply_run()...\n");
fasttime_t time1 = gettime();
matrix_multiply_run(A, B, C);
fasttime_t time2 = gettime();
if (should_print) {
printf("---- RESULTS ----\n");
printf("Result: \n");
print_matrix(C);
printf("---- END RESULTS ----\n");
}
if (show_usec) {
double elapsed = tdiff(time1, time2);
printf("Elapsed execution time: %f usec\n",
elapsed * (1000.0 * 1000.0));
} else {
double elapsed = tdiff(time1, time2);
printf("Elapsed execution time: %f sec\n", elapsed);
}
return 0;
}