I write a test program as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <time.h>
#define PACKET_SIZE 500
#define LOOP_COUNT 30000
int g_sndsucc = 0;
int g_sndfail = 0;
const int C_IPC_KEY = 0x00231a95;
const int COUNT_SIZE = 10000;
unsigned long g_count = 0;
unsigned long g_t1 = 0;
struct timeval s1, s2, s3, s4;
int main(int argc, char* argv[])
{
int ipckey = C_IPC_KEY;
if(argc > 1)
{
ipckey = atoi(argv[1]);
printf("ipckey is %d\n", ipckey);
}
int qid = msgget(ipckey, IPC_CREAT | 0666);
if(qid <= 0)
{
printf("msgget err: %d \n", errno);
return 0;
}
char data[PACKET_SIZE];
memset(data, 'a', PACKET_SIZE-1);
data[PACKET_SIZE-1] = '\0';
*((long *)data) = 0;
int ret = 0;
struct timeval start;
gettimeofday (&start, NULL);
while(1)
{
*((long *)data) +=1;
gettimeofday (&s1, NULL);
ret = msgsnd(qid, data, PACKET_SIZE,0);
gettimeofday (&s2, NULL);
if(ret != 0)
{
g_sndfail ++;
}
else
{
g_sndsucc ++;
}
g_count++;
g_t1 += (s2.tv_sec-s1.tv_sec)*1000000 + (s2.tv_usec-s1.tv_usec);
if ( g_count >= 10000)
{
printf("STAT1: t1 : %f\n",
10000000000.0 / g_t1);
g_count = 0;
g_t1 = 0;
}
usleep(1000);
}
return 0;
}
I create 100 same processes to msgsnd , and on suse, each process's msgsnd tps only reaches 50/s.
But on AIX5 the msgsnd tps can reaches 10000/s.
Does anyone know why the performance of IPC on linux when multi-processes is so poor?
And how to increase the performance on linux??
BTW, the kenel version of suse is linux 3.0.13
I checked the source code of the msgget in linux3.8.
When the thread did not get the msg lock, it is not release cpu and sleep some time.
Instead it will call ipc_lock_by_ptr(&msq->q_perm); frequently.
So the cpu usage will be very high, and the collision rate will grow rapidly when the threads increas.
Related
I'm trying to investigate the relationship between accessing array elements and cache misses. I wrote the following codes.
#include <asm/unistd.h>
#include <linux/perf_event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <inttypes.h>
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags) {
int ret;
ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
group_fd, flags);
return ret;
}
int main(int argc, char **argv) {
struct perf_event_attr pe;
long long count;
int fd;
char *chars, c;
uint64_t n = 100000000;
int step = 64;
if (argc > 1) {
step = atoi(argv[1]);
}
chars = malloc(n * sizeof(char));
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HW_CACHE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_CACHE_L1D |
PERF_COUNT_HW_CACHE_OP_READ << 8 |
PERF_COUNT_HW_CACHE_RESULT_MISS << 16;
pe.disabled = 1;
pe.exclude_kernel = 1;
pe.exclude_hv = 1;
fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
fprintf(stderr, "Error opening leader %llx\n", pe.config);
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < n; i++) {
chars[i] = 1;
}
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
// Read from memory
for (size_t i = 0; i < n; i += step) {
c = chars[i];
}
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
read(fd, &count, sizeof(long long));
printf("%lld\n", count);
close(fd);
free(chars);
}
It is easy to know that only n/step elements in the array chars are accessed and assigned to c. I think the number of cache misses should be n/step if step is larger than the cache line (64 usually). There is no problem when step is small, i.e.,the printed number of count is about n/step. However, if step is a large number, e.g., 1000000, count is equal to about 2n/step. This has confused me for a long time. Could anyone explain this odd result?
I've created a table of mq file descriptors and I'm trying to pass numbers from stdin by one of them.
I'm using notification using threads and when a number occures in one of the queues it should print for example "Number: 1 from queue: 3".
Here's my code:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <mqueue.h>
#define MAX_LENGTH 20
#define ERR(source) (\
fprintf(stderr, "%s:%d\n", __FILE__, __LINE__),\
perror(source),\
kill(0, SIGKILL),\
exit(EXIT_FAILURE)\
)
static void not_func(union sigval sv) {
mqd_t queue;
uint8_t number;
unsigned msg_prio;
queue = *((mqd_t*)sv.sival_ptr);
static struct sigevent not;
not.sigev_notify = SIGEV_THREAD;
not.sigev_notify_function = not_func;
not.sigev_value.sival_ptr = &queue;
if(mq_notify(queue, ¬)<0) ERR("mq_notify");
for(;;) {
if(mq_receive(queue, (char*)&number, 1, &msg_prio)<1) {
if(errno == EAGAIN) break;
else ERR("mq_receive");
printf("Number: %d from queue: %d", number, msg_prio);
}
}
}
void get_queue_name(int nr, char *str) {
snprintf(str, MAX_LENGTH, "/queue%d", nr);
}
mqd_t create_message_queue(int nr) {
mqd_t queue;
char name[MAX_LENGTH] = "";
get_queue_name(nr, name);
struct mq_attr attr;
attr.mq_maxmsg = 10;
attr.mq_msgsize = 1;
if((queue = TEMP_FAILURE_RETRY(mq_open(name, O_RDWR|O_NONBLOCK|O_CREAT, 0600, &attr))) == (mqd_t)-1) ERR("mq open in");
static struct sigevent not;
not.sigev_notify = SIGEV_THREAD;
not.sigev_notify_function = not_func;
not.sigev_value.sival_ptr = &queue;
if(mq_notify(queue, ¬)<0) ERR("mq_notify");
return queue;
}
void delete_message_queue(mqd_t queue, int nr) {
char name[MAX_LENGTH] = "";
get_queue_name(nr, name);
mq_close(queue);
if(mq_unlink(name)) ERR("mq_unlink");
}
void usage(void) {
fprintf(stderr, "USAGE: mqueue n\n");
fprintf(stderr, "100 > n > 0 - number of children\n");
exit(EXIT_FAILURE);
}
int main(int argc, char **argv) {
int n, i;
char strnumber[MAX_LENGTH];
int number;
mqd_t *queues;
srand(time(NULL));
if(argc != 2) usage();
n = atoi(argv[1]);
if(n<=0 || n>=100) usage();
queues = (mqd_t*)malloc(sizeof(mqd_t) * n);
if(queues == NULL) ERR("malloc");
for(i = 0; i < n; i++) {
queues[i] = create_message_queue(i+1);
}
while(fgets(strnumber, MAX_LENGTH, stdin)!=NULL) {
number = (uint8_t)atoi(strnumber);
if(number<=0) continue;
int randomQueue = rand()%n;
if(TEMP_FAILURE_RETRY(mq_send(queues[randomQueue], (const char *)&number, 1, (unsigned)randomQueue))) ERR("mq_send");
}
for(i = 0; i < n; i++) {
delete_message_queue(queues[i], i+1);
}
free(queues);
return EXIT_SUCCESS;
}
When I execute my code nothing happens:
or I have such an error:
You pass a pointer to queue (which is a local variable) to the thread (via not.sigev_value.sival_ptr) which runs after that variable goes out of scope. So it gets a dangling pointer.
Either pass the descriptor by value (if it fits in sigval; it should), or store it on the heap (with new/malloc) and pass that pointer.
For some reason I am getting a segmentation fault before any of my code is actually executed in the main() function. I have tried following the line of execution by putting in printfs but nothing is actually executed. I don't see anything in my program that would be causing a stack overflow, as I hardly even use memory.
If someone has better eyes than me and can spot this error it would be very much appreciated!
Main:
#include "../inc/protos.h"
HistogramData *histogram_data;
bool signal_caught = false;
sem_t *semaphore_id;
int letter_count[kLetterCount] = { 0 };
int wait_time = 0;
int main(void)
{
int shared_memory_id = 0;
key_t shared_memory_key = 0;
char buffer[kBufferLength] = { 0 };
int heads = 0;
int tails = 0;
printf("1");
histogram_data->signal_caught = false;
signal(SIGINT, signal_handler);
printf("2");
//Get the key to the allocated shared memory
shared_memory_key = ftok("/tmp", 'M');
if(shared_memory_key == -1)
{
printf("(CONSUMER) Cannot allocate key.\n");
return 1;
}
printf("3");
//Look for shared memory every 10 seconds until it finds it
while(true)
{
if((shared_memory_id = shmget(shared_memory_key, sizeof(histogram_data), 0)) == -1)
{
printf("4");
printf("(CONSUMER) Shared Memory does not exist. Please run the Producer program.\n");
sleep(kSleepTime);
}
else
{
printf("5");
break;
}
}
printf("(CONSUMER) Our Shared Memory ID is %d.\n", shared_memory_id);
//Attach the structure to the shared memory
histogram_data = (HistogramData*) shmat(shared_memory_id, NULL, 0);
if(histogram_data == NULL)
{
printf("(CONSUMER) Cannot attach to Shared Memory.\n");
return 3;
}
semaphore_id = sem_open("/HISTOGRAM_SEM", O_CREAT, S_IRUSR | S_IWUSR, 1);
signal(SIGALRM, alarm_handler);
//Set the watchdog timer to 2 seconds.
alarm(kAlarmSeconds);
//Detach from shared memory
shmdt(histogram_data);
return 0;
}
void signal_handler(int signal_number)
{
printf ("(CONSUMER) Received a signal. SIGINT ID is %d\n", signal_number);
histogram_data->signal_caught = true;
// Send SIGINT to Producer2
kill(histogram_data->producer2_pid, SIGINT);
// Send SIGINT to Producer1
kill(histogram_data->producer1_pid, SIGINT);
}
void print_line(int num)
{
int hundreds = num / 100;
num = num % 100;
int tens = num / 10;
num = num % 10;
int ones = num;
int i = 0;
for(i = 0; i < hundreds; i++)
{
printf("*");
}
for(i = 0; i < tens; i++)
{
printf("+");
}
for(i = 0; i < ones; i++)
{
printf("-");
}
printf("\n");
}
void display_histogram(int letter_count[])
{
int i = 0;
printf("\n********** HISTOGRAM **********\n");
for(i = 0; i < kLetterCount; i++)
{
printf("%c-%03d ", i + 65, letter_count[i]);
print_line(letter_count[i]);
}
}
void alarm_handler(int signal_number)
{
int wait_time = 0;
sem_wait(semaphore_id);
int i = 0;
for(i = 0; i < kDCReads; i++)
{
int* read_index = &histogram_data->read_index;
if(histogram_data->circular_buffer[*read_index] != 0)
{
int read_data = histogram_data->circular_buffer[*read_index];
histogram_data->circular_buffer[*read_index] = 0;
++letter_count[read_data - 65];
if(*read_index == kCircleBufferSize)
{
*read_index = 0;
}
if(*read_index == histogram_data->write_index)
{
break;
}
}
}
if(signal_caught == true)
{
//Read and write indexes from the histogram data structure
int* read_index = &histogram_data->read_index;
int* write_index = &histogram_data->write_index;
//Read data from buffer
while(*read_index != *write_index)
{
if(histogram_data->circular_buffer[*read_index])
{
//Data read in from the circular buffer
int read_data = histogram_data->circular_buffer[*read_index];
//Mark element as read
histogram_data->circular_buffer[*read_index] = 0;
++letter_count[read_data - 65];
//Increment the elements
(*read_index)++;
if(*read_index == 256)
{
*read_index = 0;
}
if(*read_index == *write_index)
{
break;
}
}
}
//Display a histogram listing
display_histogram(letter_count);
return;
}
wait_time++;
if(wait_time >= 5)
{
wait_time = 0;
display_histogram(letter_count);
}
//Release semaphore lock
sem_post(semaphore_id);
//Set the alarm for the watchdog to be two seconds
alarm(kAlarmSeconds);
//Reactivate watchdog signal
signal(signal_number, alarm_handler);
}
protos.h:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <signal.h>
#include <semaphore.h>
#define kCircleBufferSize 256
#define kBufferLength 126
#define kLetterCount 20
#define kDCReads 60
#define kAlarmSeconds 2
#define kSleepTime 10
typedef struct HistogramData HistogramData;
struct HistogramData
{
int read_index;
int write_index;
int is_wrap_around;
pid_t producer1_pid;
pid_t producer2_pid;
char circular_buffer[kCircleBufferSize];
bool signal_caught;
};
void signal_handler(int signal_number);
void print_line(int num);
void display_histogram(int letter_count[]);
void alarm_handler(int signal_number);
For some reason I am getting a segmentation fault before any of my code is actually executed in the main() function.
One of your preloaded data structures is likely to be causing overflow in the stack. You also have a lot of buffering going on to the output and, additionally, you have several places where you use printf() but do not append the newline \nto flush the console buffer. Alternatively, you can follow #sabbahillel's comment by putting fflush() after your printf() statements.
You create histogram_data as a pointer to HistogramData, but don't create a HistogramData object. Then, when you call histogram_data->signal_caught = false in main, you program dereferences a NULL pointer.
Instead, allocate memory for HistogramData before using the pointer (for example, histogram_data = malloc(sizeof *histogram_data);). Don't forget to free it later, too.
The task was to create simulation of warehouse's work. Producers (in an amount of argv[2]) create random number of "goods" (totally argv[1]), and consumers (in an amount of argv[3]) get random number of these goods. The full code is below.
I got segmentation error and tried to debug it and got the following:
Program received signal SIGSEGV, Segmentation fault.
__new_sem_init (sem=0x37, pshared=0, value=1) at sem_init.c:44
44 sem_init.c: No such file or directory
I think the problem is in address-of operator here
sem_init(&(shared->mutex), 0, 1);
How should I change the code to make it work?
Thanks a lot!
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>
#define NBUFF 10
#define MAXNTHREADS 100
#define min( a, b ) ( ( a < b) ? a : b )
int nitems, nproducers, nconsumers;
typedef struct shared_s
{
int buff[NBUFF];
int nput;
int nputval;
int nget;
int ngetval;
sem_t mutex, nempty, nstored;
} sharedtype;
int main(int argc, char **argv)
{
sharedtype * shared;
key_t key;
int shmid, semid;
int i, j, prodcount[MAXNTHREADS], conscount[MAXNTHREADS];
shared = mmap(NULL, sizeof(sharedtype),
PROT_READ | PROT_WRITE, MAP_SHARED, -1, 0);
/* Wrong argv */
if (argc != 4)
{
printf("usage: newconsumer <#items> <#producers> <#consumers>\n");
exit(1);
}
nitems = atoi(argv[1]);
nproducers = min(atoi(argv[2]), MAXNTHREADS);
nconsumers = min(atoi(argv[3]), MAXNTHREADS);
pid_t chpidpr [nproducers];
pid_t chpidcon [nconsumers];
/* initilising semaphores */
sem_init(&(shared->mutex), 0, 1);
sem_init(&(shared->nempty), 0, NBUFF);
sem_init(&(shared->nstored), 0, 0);
for (i = 0; i < nproducers; i++) {
prodcount[i] = 0;
switch (chpidpr[i] = fork())
{
case -1:
printf("fork error");
return 1;
case 0:
for (;;)
{
sem_wait(&shared->nempty);
sem_wait(&shared->mutex);
if (shared->nput >= nitems)
{
sem_post(&(shared->nstored));
sem_post(&(shared->nempty));
sem_post(&(shared->mutex));
return 0;
}
shared->buff[(shared->nput) %NBUFF] = shared->nputval;
(shared->nput)++;
(shared->nputval)++;
sem_post(&(shared->mutex));
sem_post(&(shared->nstored));
prodcount[i] += 1;
}
}
}
for (i = 0; i < nproducers; i++)
{
printf("producer count[%d] = %d\n", i, prodcount[i]);
}
for (i = 0; i < nconsumers; i++) {
conscount[i] = 0;
switch (chpidcon[i] = fork())
{
case -1:
printf("error");
return 1;
case 0:
for (;;)
{
sem_wait(&(shared->nstored));
sem_wait(&(shared->mutex));
if (shared->nget >= nitems)
{
sem_post(&(shared->nstored));
sem_post(&(shared->mutex));
return 0;
}
j = shared->nget % NBUFF;
if (shared->buff[j] != shared->ngetval)
{
printf("error: buff[%d] = %d\n", j, shared->buff[j]);
}
shared->nget++;
shared->ngetval++;
sem_post(&(shared->mutex));
sem_post(&(shared->nempty));
conscount[i] += 1;
}
}
}
for (i = 0; i < nconsumers; i++)
{
printf("consumer count[%d] = %d\n", i, conscount[i]);
}
/* destroying semaphores */
sem_destroy(&(shared->mutex));
sem_destroy(&(shared->nempty));
sem_destroy(&(shared->nstored));
exit(0);
}
It looks like your mmap call has failed and return -1. You aren't checking for this condition.
I did a quick addition, and it looks like mutex is at an offset of 56, or 0x38 from the base of sharedtype. Based on the crash report, sem = 0x37, which would be the address of shared->mutex if shared == -1.
I can't find any documentation on why one would call mmap with fd == -1, but I think this may be the source of the issue, combined with not validating the result.
How can I calculate or estimate the RTT (Round Trip Time) between client and server?
A tutorial or sample addressing this can also help.
Here what I do:
#include <rpc/rpc.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/times.h>
#include <fcntl.h>
#include <time.h>
int main(int argc, char *argv[]) {
enum clnt_stat status;
CLIENT *handle;
struct timeval t;
clock_t rtime;
struct tms dumm;
int count = 100000;
int i;
time_t now;
char stamp[27];
int programm;
int version;
if (argc != 4) {
printf("Usage: rpcping <host> <program> <version>\n");
exit(1);
}
/*
* Create Client Handle
*/
programm = atoi(argv[2]);
version = atoi(argv[3]);
handle = clnt_create(argv[1], programm, version, "tcp");
if (handle == NULL) {
printf("clnt failed\n");
exit(1);
}
/*
* use 30 seconds timeout
*/
t.tv_sec = 30;
t.tv_usec = 0;
while (1) {
rtime = times(&dumm);
for (i = 0; i < count; i++) {
status = clnt_call(handle, 0, (xdrproc_t) xdr_void,
NULL, (xdrproc_t) xdr_void, NULL, t);
if (status == RPC_SUCCESS) { /* NOP */ }
}
now = time(NULL);
ctime_r(&now, stamp);
stamp[strlen(stamp) - 1] = '\0';
fprintf(stdout, "[%s]: Speed: %2.4fs.\n", stamp,
count / ((double) (times(&dumm) - rtime) / (double) sysconf(_SC_CLK_TCK)));
fflush(stdout);
}
clnt_destroy(handle);
}
I have a multithread version as well
https://gist.github.com/2401404
tigran.