The vector order in the following program consumes 8MB when loaded. I'm trying to perform memory mapping using mmap and map a small CHUNK_SIZEiteratively to avoid memory overhead. The CHUNK_SIZEis 10240 and the program causes segmentation fault when accessing the index 11264 as VECTOR(*order)[act_rank++] = actvect;.
Now, I have the following questions:
- After the first invocation of the function
memory_map_order_iterative(), (without iterative or 2nd invocation) how the vector can access up to index11263where the chunk size is10240? - When invoking the function
memory_map_order_iterative()(iteratively), after 2nd invocation the order vector should be accessed from index10240to20479, then why it is causing segmentation fault?
Any suggestions will be a great help.
#include <igraph.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#define CHUNK_SIZE 10240
igraph_error_t unmap_order(igraph_integer_t **mapped_order, igraph_integer_t chunk_size){
if (munmap(*mapped_order, chunk_size * sizeof(igraph_integer_t)) == -1) {
perror("munmap");
return IGRAPH_EFILE;
}
*mapped_order = NULL;
return IGRAPH_SUCCESS;
}
igraph_error_t memory_map_order_iterative(igraph_vector_int_t *order, const char *order_filename, igraph_integer_t **mapped_order, igraph_integer_t no_of_elements, igraph_integer_t *remaining_elements, igraph_integer_t *offset) {
int fd;
fd = open(order_filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror("open");
return IGRAPH_EFILE;
}
if (ftruncate(fd, no_of_elements * sizeof(igraph_integer_t)) == -1) {
perror("ftruncate");
close(fd);
return IGRAPH_EFILE;
}
igraph_integer_t chunk_size = (*remaining_elements > CHUNK_SIZE) ? CHUNK_SIZE : *remaining_elements;
*mapped_order = mmap(NULL, chunk_size * sizeof(igraph_integer_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, (*offset) * sizeof(igraph_integer_t));
if (*mapped_order == MAP_FAILED) {
perror("mmap");
close(fd);
return IGRAPH_EFILE;
}
*offset += chunk_size;
*remaining_elements -= chunk_size;
close(fd);
igraph_vector_int_view(order, *mapped_order, chunk_size);
return IGRAPH_SUCCESS;
}
igraph_error_t igraph_bfs(const igraph_t *graph,
igraph_vector_int_t *order,
void *extra) {
const igraph_integer_t no_of_nodes = igraph_vcount(graph);
igraph_dqueue_int_t Q;
igraph_integer_t actroot = 0;
igraph_integer_t act_rank = 0;
IGRAPH_DQUEUE_INT_INIT_FINALLY(&Q, 100);
igraph_integer_t *mapped_order = NULL;
igraph_integer_t remaining_elements = 999998;
igraph_integer_t offset = 0;
igraph_error_t is_map_success;
is_map_success = memory_map_order_iterative(order, "/tmp/orders_map.bin", &mapped_order, no_of_nodes, &remaining_elements, &offset);
if (is_map_success != IGRAPH_SUCCESS) {
return is_map_success;
}
while (1) {
IGRAPH_CHECK(igraph_dqueue_int_push(&Q, actroot));
IGRAPH_CHECK(igraph_dqueue_int_push(&Q, 0));
while (!igraph_dqueue_int_empty(&Q)) {
igraph_integer_t actvect = igraph_dqueue_int_pop(&Q);
if (order) {
if(act_rank>0 && act_rank%CHUNK_SIZE==0){
igraph_error_t unmap_error = unmap_order(&mapped_order, CHUNK_SIZE);
if (unmap_error != IGRAPH_SUCCESS) {
return unmap_error;
}
igraph_error_t is_map_success;
is_map_success = memory_map_order_iterative(order, "/tmp/orders_map.bin", &mapped_order, no_of_nodes, &remaining_elements, &offset);
if (is_map_success != IGRAPH_SUCCESS) {
return is_map_success;
}
}
VECTOR(*order)[act_rank++] = actvect;
}
}
}
return IGRAPH_SUCCESS;
}
int main(void) {
igraph_t graph;
FILE *file = fopen("random_graph.edgelist", "r");
if (!file) {
return 1;
}
if (igraph_read_graph_edgelist(&graph, file, 0, IGRAPH_UNDIRECTED) == IGRAPH_SUCCESS) {
} else {
return 1;
}
igraph_vector_int_t order;
igraph_vector_int_init(&order, 0);
igraph_bfs(&graph, &order,/*extra=*/ NULL);
igraph_destroy(&graph);
return 0;
}
I'm expecting to map order using mmap and access it chunk by chunk as
chunk1: from 0 to 10239
chunk1: from 10240 to 20479
and so on.
I tried mapping the full length of the order without mapping chunk by chunk as given below it works well and doesn't get segmentation fault. The issue is mapping the full length of order doesn't reduce memory consumption.
void unmap(igraph_integer_t *mapped_order, size_t size) {
if (munmap(mapped_order, size) == -1) {
perror("munmap");
}
}
igraph_error_t memory_map_order(const char *order_filename, igraph_integer_t **mapped_order, igraph_integer_t no_of_elements, igraph_vector_int_t *order) {
int fd;
fd = open(order_filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror("open");
return IGRAPH_EFILE;
}
if (ftruncate(fd, no_of_elements * sizeof(igraph_integer_t)) == -1) {
perror("ftruncate");
close(fd);
return IGRAPH_EFILE;
}
*mapped_order = mmap(NULL, no_of_elements * sizeof(igraph_integer_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (*mapped_order == MAP_FAILED) {
perror("mmap");
close(fd);
return IGRAPH_EFILE;
}
close(fd);
igraph_vector_int_view(order, *mapped_order, no_of_elements);
return IGRAPH_SUCCESS;
}