【问题标题】:How to modify or create a struct depending on argument?如何根据参数修改或创建结构?
【发布时间】:2022-01-12 02:30:16
【问题描述】:

我必须使用 C 进一步开发一个模拟器,能够模拟不同的缓存类型(直接、n 路关联、完全关联)。现在我的代码可以模拟直接映射的缓存,但它不能模拟任何其他类型。

我的代码 我的 C 文件:

   /*
 * CS3375 Computer Architecture
 * Course Project
 * Cache Simulator Design and Development
 * FALL 2017
 * By Yong Chen
 */

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include "cachesim.h"
int main(int argc, char *argv[])
{
    char type;
    if (argc != 3) {
        printf("Usage: %s <direct> <trace file name>\n", argv[0]);
        return 1;
    }

#ifdef DBG
    printf("BLOCK SIZE = %d Bytes\n", BLOCK_SIZE);
    printf("%d-WAY\n", WAY_SIZE);
    printf("CACHE SIZE = %d Bytes\n", CACHE_SIZE);
    printf("NUMBER OF BLOCKS = %d\n", NUM_BLOCKS);
    printf("NUMBER OF SETS = %d\n", NUM_SETS);
    printf("\n");
#endif
    struct direct_mapped_cache d_cache;
    char* trace_file_name = argv[2];
    char mem_request[20];
    uint64_t address;
    FILE *fp;


    /* Initialization */
    for (int i=0; i<NUM_BLOCKS; i++) {
        d_cache.valid_field[i] = 0;
        d_cache.dirty_field[i] = 0;
        d_cache.tag_field[i] = 0;
    }

    d_cache.hits = 0;
    d_cache.misses = 0;

    /* Opening the memory trace file */
    fp = fopen(trace_file_name, "r");

    /*Checks if argument specified direct-mapped cache*/
    if (strncmp(argv[1], "direct", 6)==0) { /* Simulating direct-mapped cache */
        /* Read the memory request address and access the cache */
        while (fgets(mem_request, 20, fp)!= NULL) {
            address = convert_address(mem_request);
            direct_mapped_cache_access(&d_cache, address);
        }
        /*Calculate Hit and Miss Rate*/
        double hit_rate = ((1.0 * d_cache.hits)/(d_cache.hits + d_cache.misses));
        double miss_rate = ((1.0 * d_cache.misses)/(d_cache.hits + d_cache.misses));
        /*Print out the results*/
        printf("\n==================================\n");
        printf("Cache type:    Direct-Mapped Cache\n");
        printf("==================================\n");
        printf("Cache Hits:    %d\n", d_cache.hits);
        printf("Cache Misses:  %d\n", d_cache.misses);
        printf("Cache Hit Rate: %f\n", hit_rate);
        printf("Cache Miss Rate: %f\n", miss_rate);
        printf("\n");
    }

    fclose(fp);

    return 0;
}

uint64_t convert_address(char memory_addr[])
/* Converts the physical 32-bit address in the trace file to the "binary" \\
 * (a uint64 that can have bitwise operations on it) */
{
    uint64_t binary = 0;
    int i = 0;

    while (memory_addr[i] != '\n') {
        if (memory_addr[i] <= '9' && memory_addr[i] >= '0') {
            binary = (binary*16) + (memory_addr[i] - '0');
        } else {
            if(memory_addr[i] == 'a' || memory_addr[i] == 'A') {
                binary = (binary*16) + 10;
            }
            if(memory_addr[i] == 'b' || memory_addr[i] == 'B') {
                binary = (binary*16) + 11;
            }
            if(memory_addr[i] == 'c' || memory_addr[i] == 'C') {
                binary = (binary*16) + 12;
            }
            if(memory_addr[i] == 'd' || memory_addr[i] == 'D') {
                binary = (binary*16) + 13;
            }
            if(memory_addr[i] == 'e' || memory_addr[i] == 'E') {
                binary = (binary*16) + 14;
            }
            if(memory_addr[i] == 'f' || memory_addr[i] == 'F') {
                binary = (binary*16) + 15;
            }
        }
        i++;
    }

#ifdef DBG
    printf("%s converted to %llu\n", memory_addr, binary);
#endif
    return binary;
}

void direct_mapped_cache_access(struct direct_mapped_cache *cache, uint64_t address)
{
    uint64_t block_addr = address >> (unsigned)log2(BLOCK_SIZE);
    uint64_t index = block_addr % NUM_BLOCKS;
    uint64_t tag = block_addr >> (unsigned)log2(NUM_BLOCKS);

#ifdef DBG
    printf("Memory address: %llu, Block address: %llu, Index: %llu, Tag: %llu ", address, block_addr, index, tag);
#endif

    if (cache->valid_field[index] && cache->tag_field[index] == tag) { /* Cache hit */
        cache->hits += 1;
#ifdef DBG
        printf("Hit!\n");
#endif
    } else {
        /* Cache miss */
        cache->misses += 1;
#ifdef DBG
        printf("Miss!\n");
#endif
        if (cache->valid_field[index] && cache->dirty_field[index]) {
            /* Write the cache block back to memory */
        }
        cache->tag_field[index] = tag;
        cache->valid_field[index] = 1;
        cache->dirty_field[index] = 0;
    }
}

我的 .h 文件:

    /*
 * CS3375 Computer Architecture
 * Course Project
 * Cache Simulator Design and Development
 * FALL 2017
 * By Yong Chen
 */

#include <stdio.h>
/* Cache block size (or cache line size) in bytes*/
#define BLOCK_SIZE  64          /*(must be power of 2). 4 Bytes = 1 Word NOTE: MUST CHANGE DEPENDING ON TYPE*/
#define WAY_SIZE    1              /* Associativity; 1-way = direct-mapped MUST CHANGE DEPENDING ON TYPE*/
#define CACHE_SIZE  32768       /* Cache capacity in bytes (must be power of 2) THIS WILL STAY FIXED*/

#define NUM_BLOCKS  (CACHE_SIZE / BLOCK_SIZE)
#define NUM_SETS  (BLOCK_SIZE/WAY_SIZE)
/*For fully associative, num sets is equal to num blocks because way size is equal to num blocks. */

/*MAY TRY LEAVING THESE VARIABLES UNDEFINED, AND THEY WILL BE SET DEPENDING ON USER INPUT.*/

#define DBG /*Prints debugging information*/

/*The data structure of direct-mapped cache*/
struct direct_mapped_cache {
    unsigned valid_field[NUM_BLOCKS];   /* Valid field */
    unsigned dirty_field[NUM_BLOCKS];   /* Dirty field; since we don't distinguish writes and \\
                                           reads in this project yet, this field doesn't really matter */
    uint64_t tag_field[NUM_BLOCKS];     /* Tag field */
    char data_field[NUM_BLOCKS][BLOCK_SIZE];  /* Data field; since we don't really fetch data, \\
                                                 this field doesn't really matter */
    int hits;                          /* Hit count */
    int misses;                        /* Miss count */
};


/*Read the memory traces and convert it to binary*/
uint64_t convert_address(char memory[]);

/*Simulate the direct-mapped cache*/
void direct_mapped_cache_access(struct direct_mapped_cache *cache, uint64_t address);

我的尝试 诚然,我是 C 语言的初学者,所以我的解决方案可能比我想象的要简单,但到目前为止我还没有找到任何答案。我考虑过根据参数更改使用“#define”定义缓存变量的位置,但我了解到“#define”是通过预处理运行的,所以这不起作用。

我也尝试为每种需要模拟的缓存类型创建多个结构类,但由于 C 中的结构变量无法在类中初始化,我也无法让它工作。

据我了解,C 中的结构也不能有构造函数,因为我也对此进行了研究。

我们将不胜感激任何帮助或朝着正确方向迈出的一步。

【问题讨论】:

  • 结构在编译时声明,不能更改。您可以使用动态分配在每个结构中放置更多或更少的数据。 C 结构不能有构造函数,我不确定如果存在它会有什么帮助。您有一个将十六进制文本转换为整数的部分,您可以使用sscanfdata_field 为每个元素分配 32kb,但未使用。

标签: c caching struct


【解决方案1】:

首先你对 struct 有一个误解:它们不是对象,而是一个数据布局,这意味着没有构造函数或析构函数(如果你需要这些特性,你将需要专门的函数)

下一个你的实际问题:“我的结构中可以有可变数量的内存吗?”

答案:

是的,但不是直接的,你需要使用像mallocfree这样的函数来动态分配和释放内存,我不会对它们做完整的解释,你会发现如何在网上很容易地使用它们.

您需要执行以下操作:

#include<stdlib.h>

struct mystruct {
    unsigned size;
    unsigned * memory;
};

typedef struct mystruct mystruct;

mystruct * mystruct_constructor(unsigned s) {
    //allocate the space of struct itself
    mystruct * ms = malloc(sizeof(mystruct));

    ms->size = s;

    //allocate the variable size array
    ms->memory = malloc(sizeof(unsigned) * s);

    return ms;
}

void mystruct_destructor(mystruct * ms) {
    free(ms->memory);
    free(ms);
}

只知道 malloc 不会初始化空间,因此其中的数据是未知的(并且可能不为零)。

至于为什么你不能定义可变大小的结构是因为你需要编译时数组(像unsigned var[X])有一个编译时定义的大小,因为当你制作这样的数组时,结构实际上包含 X 元素数组类型。

意思是:

#define N whatever_value_you_want

struct {
    unsigned item[N + 1]; // valid because it can be known at compile-time
};

具有与以下相同(正常情况下)的布局:

struct {
    unsigned item_0;
    unsigned item_1;
    unsigned item_2;
    ...
    unsigned item_N;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2019-05-22
    • 2015-05-20
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    相关资源
    最近更新 更多