ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I have this function that executes pretty much forever until the application is shutdown. Once it starts running the CPU usage goes through the roof. Is there any way to help prevent this? It basically runs waiting for work to do. Work will be assigned to me->queue, and the qlen increased. When this sees qlen is greater than 0 it will pickup the next piece of data to process and process it.
It works great except the high CPU usage.
Code:
void *packetsqueezer_function (void *dummyPtr)
{
struct worker *me;
struct packet *thispacket;
struct iphdr *iph;
me = dummyPtr;
thispacket = NULL; // Initialize pointer for the queued packet.
iph = NULL; // Initialize pointer for the IP header.
while (me->state >=0) {
/* Lets get the next packet from the queue. */
pthread_mutex_lock(&me->queue.lock); // Grab lock on the queue.
if (me->queue.qlen > 0){ // Only get a packet if there is one.
printf("Queue has %d packets!\n", me->queue.qlen);
thispacket = me->queue.next; // Get the next packet in the queue.
me->queue.next = thispacket->next; // Move the next packet forward in the queue.
me->queue.qlen -= 1; // Need to decrease the packet cound on this queue.
thispacket->next = NULL;
thispacket->prev = NULL;
}
pthread_mutex_unlock(&me->queue.lock); // Lose lock on the queue.
if (thispacket != NULL){ // If a packet was taken from the queue.
iph = (struct iphdr *)thispacket->data;
printf("ip_length=%u\n",ntohs(iph->tot_len));
nfq_set_verdict(thispacket->hq, thispacket->id, NF_ACCEPT, ntohs(iph->tot_len), thispacket->data);
free(thispacket);
thispacket = NULL;
}
//sleep(1);
}
return 0;
}
The obvious crude solution is to put the sleep(1) back in.
If you do that, you should at least make it else sleep(1);
rather than just sleep(1); so it can't make work back up.
The sleep does an imperfect job of eliminating the wasted CPU time and introduces some latency that might be annoying. So it might be worth the effort to solve the problem "correctly". But it does solve most of the problem with no significant programming effort, so maybe that is preferable to solving it "correctly".
I don't happen to recall enough about programming things you can wait for to give you detailed advice on how to code it "correctly". Also, that probably requires looking at the source side of queue in order to know what changes are needed there. The crude solution can be done within just the code you quoted.
The obvious crude solution is to put the sleep(1) back in.
If you do that, you should at least make it else sleep(1);
rather than just sleep(1); so it can't make work back up.
The sleep does an imperfect job of eliminating the wasted CPU time and introduces some latency that might be annoying. So it might be worth the effort to solve the problem "correctly". But it does solve most of the problem with no significant programming effort, so maybe that is preferable to solving it "correctly".
I don't happen to recall enough about programming things you can wait for to give you detailed advice on how to code it "correctly". Also, that probably requires looking at the source side of queue in order to know what changes are needed there. The crude solution can be done within just the code you quoted.
I didn't add the security exception needed to follow your link. Just looking at the snip of code you quoted.
I assume fd is the end of a pipe. So the question is what does the recv call do when the pipe is empty:
Return 0, causing the code you quoted to consume lots of CPU time?
Stall inside recv causing it not to consume excess CPU time.
Return an error code (negative) so whether excess CPU time is consumed depends on what is done outside the quoted while.
I've used pipes in too many systems in too many ways to remember now which is the typical Linux behavior and/or what choices in creating or opening a pipe determine the answer to the above question. You should be able to look up documentation for whatever functions you used to create and open the pipe in order to get that answer.
I think Ill add another if (me->queue.qlen > 0){ statement before the muxtex lock with an else{ sched_yield()} statement. That should slow it down when the queue is empty. I dont know how efficient it is, but its got to be better than what its doing now.
For multiple process you are going to have to use a signal. Man signal.
In the case of multiple processes, the process originating the work would have to signal the process that handles the work, when there is work to be done.
edit:
Never mind. I reread the first post and saw that the work will appear at a location that is internal to the application. Hence multi threads and posix signaling is definitely the way to go.
Once I added waiting in the thread when there is no work it fixed the high CPU usage issue. Everything runs much smoother now.
Thanks everyone.
edit*
Here is the code if anyone wanted to see it.
Code:
void *worker_function (void *dummyPtr)
{
struct worker *me;
struct packet *thispacket;
struct iphdr *iph;
me = dummyPtr;
thispacket = NULL; // Initialize pointer for the queued packet.
iph = NULL; // Initialize pointer for the IP header.
while (me->state >=0) {
/* Lets get the next packet from the queue. */
pthread_mutex_lock(&me->queue.lock); // Grab lock on the queue.
if (me->queue.qlen == 0){ // If there is no work wait for some.
pthread_cond_wait(&me->signal, &me->queue.lock);
}
if (me->queue.next != NULL){ // Make sure there is work.
printf("Queue has %d packets!\n", me->queue.qlen);
thispacket = me->queue.next; // Get the next packet in the queue.
me->queue.next = thispacket->next; // Move the next packet forward in the queue.
me->queue.qlen -= 1; // Need to decrease the packet cound on this queue.
thispacket->next = NULL;
thispacket->prev = NULL;
}
pthread_mutex_unlock(&me->queue.lock); // Lose lock on the queue.
if (thispacket != NULL){ // If a packet was taken from the queue.
iph = (struct iphdr *)thispacket->data;
printf("ip_length=%u\n",ntohs(iph->tot_len));
nfq_set_verdict(thispacket->hq, thispacket->id, NF_ACCEPT, ntohs(iph->tot_len), thispacket->data);
free(thispacket);
thispacket = NULL;
}
}
return 0;
}
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.