aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2006-12-06 23:36:54 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:39:34 -0500
commit51de4d90852ba4cfa5743594ec4a7f158b52dc43 (patch)
tree27ee40313c79c3c5fa2ef86fc059cf991c92e8e2
parent68062b86fc0f480b806d270a8278709a5a41bb67 (diff)
[PATCH] taskstats: use nla_reserve() for reply assembling
Currently taskstats_user_cmd()/taskstats_exit() do: 1) allocate stats 2) fill stats 3) make a temporary copy on stack (236 bytes) 4) copy that copy to skb 5) free stats With the help of nla_reserve() we can operate on skb->data directly, thus avoiding all these steps except 2). So, before this patch: // copy *stats to skb->data int mk_reply(skb, ..., struct taskstats *stats); fill_pid(stats); mk_reply(skb, ..., stats); After: // return a pointer to skb->data struct taskstats *mk_reply(skb, ...); stat = mk_reply(skb, ...); fill_pid(stats); Shrinks taskatsks.o by 162 bytes. A stupid benchmark (send one million TASKSTATS_CMD_ATTR_PID) shows the real user sys before: 4.02 0.06 3.96 4.02 0.04 3.98 4.02 0.04 3.97 after: 3.86 0.08 3.78 3.88 0.10 3.77 3.89 0.09 3.80 but this looks suspiciously good. Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Acked-by: Shailabh Nagar <nagar@watson.ibm.com> Cc: Balbir Singh <balbir@in.ibm.com> Cc: Jay Lan <jlan@sgi.com> Cc: Thomas Graf <tgraf@suug.ch> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--kernel/taskstats.c86
1 files changed, 44 insertions, 42 deletions
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index d2a41339f37b..b0aad99c4f8d 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -185,6 +185,7 @@ static int fill_pid(pid_t pid, struct task_struct *tsk,
185 } else 185 } else
186 get_task_struct(tsk); 186 get_task_struct(tsk);
187 187
188 memset(stats, 0, sizeof(*stats));
188 /* 189 /*
189 * Each accounting subsystem adds calls to its functions to 190 * Each accounting subsystem adds calls to its functions to
190 * fill in relevant parts of struct taskstsats as follows 191 * fill in relevant parts of struct taskstsats as follows
@@ -227,6 +228,8 @@ static int fill_tgid(pid_t tgid, struct task_struct *first,
227 228
228 if (first->signal->stats) 229 if (first->signal->stats)
229 memcpy(stats, first->signal->stats, sizeof(*stats)); 230 memcpy(stats, first->signal->stats, sizeof(*stats));
231 else
232 memset(stats, 0, sizeof(*stats));
230 233
231 tsk = first; 234 tsk = first;
232 do { 235 do {
@@ -343,9 +346,9 @@ static int parse(struct nlattr *na, cpumask_t *mask)
343 return ret; 346 return ret;
344} 347}
345 348
346static int mk_reply(struct sk_buff *skb, int type, u32 pid, struct taskstats *stats) 349static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
347{ 350{
348 struct nlattr *na; 351 struct nlattr *na, *ret;
349 int aggr; 352 int aggr;
350 353
351 aggr = TASKSTATS_TYPE_AGGR_TGID; 354 aggr = TASKSTATS_TYPE_AGGR_TGID;
@@ -353,20 +356,23 @@ static int mk_reply(struct sk_buff *skb, int type, u32 pid, struct taskstats *st
353 aggr = TASKSTATS_TYPE_AGGR_PID; 356 aggr = TASKSTATS_TYPE_AGGR_PID;
354 357
355 na = nla_nest_start(skb, aggr); 358 na = nla_nest_start(skb, aggr);
356 NLA_PUT_U32(skb, type, pid); 359 if (nla_put(skb, type, sizeof(pid), &pid) < 0)
357 NLA_PUT_TYPE(skb, struct taskstats, TASKSTATS_TYPE_STATS, *stats); 360 goto err;
361 ret = nla_reserve(skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats));
362 if (!ret)
363 goto err;
358 nla_nest_end(skb, na); 364 nla_nest_end(skb, na);
359 365
360 return 0; 366 return nla_data(ret);
361nla_put_failure: 367err:
362 return -1; 368 return NULL;
363} 369}
364 370
365static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info) 371static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
366{ 372{
367 int rc = 0; 373 int rc = 0;
368 struct sk_buff *rep_skb; 374 struct sk_buff *rep_skb;
369 struct taskstats stats; 375 struct taskstats *stats;
370 void *reply; 376 void *reply;
371 size_t size; 377 size_t size;
372 cpumask_t mask; 378 cpumask_t mask;
@@ -389,36 +395,36 @@ static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
389 size = nla_total_size(sizeof(u32)) + 395 size = nla_total_size(sizeof(u32)) +
390 nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); 396 nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
391 397
392 memset(&stats, 0, sizeof(stats));
393 rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, &reply, size); 398 rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, &reply, size);
394 if (rc < 0) 399 if (rc < 0)
395 return rc; 400 return rc;
396 401
402 rc = -EINVAL;
397 if (info->attrs[TASKSTATS_CMD_ATTR_PID]) { 403 if (info->attrs[TASKSTATS_CMD_ATTR_PID]) {
398 u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]); 404 u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
399 rc = fill_pid(pid, NULL, &stats); 405 stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid);
400 if (rc < 0) 406 if (!stats)
401 goto err; 407 goto nla_err;
402 408
403 if (mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid, &stats)) 409 rc = fill_pid(pid, NULL, stats);
404 goto nla_put_failure; 410 if (rc < 0)
411 goto nla_err;
405 } else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) { 412 } else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) {
406 u32 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]); 413 u32 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
407 rc = fill_tgid(tgid, NULL, &stats); 414 stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);
408 if (rc < 0) 415 if (!stats)
409 goto err; 416 goto nla_err;
410 417
411 if (mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid, &stats)) 418 rc = fill_tgid(tgid, NULL, stats);
412 goto nla_put_failure; 419 if (rc < 0)
413 } else { 420 goto nla_err;
414 rc = -EINVAL; 421 } else
415 goto err; 422 goto err;
416 }
417 423
418 return send_reply(rep_skb, info->snd_pid); 424 return send_reply(rep_skb, info->snd_pid);
419 425
420nla_put_failure: 426nla_err:
421 rc = genlmsg_cancel(rep_skb, reply); 427 genlmsg_cancel(rep_skb, reply);
422err: 428err:
423 nlmsg_free(rep_skb); 429 nlmsg_free(rep_skb);
424 return rc; 430 return rc;
@@ -453,7 +459,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
453{ 459{
454 int rc; 460 int rc;
455 struct listener_list *listeners; 461 struct listener_list *listeners;
456 struct taskstats *tidstats; 462 struct taskstats *stats;
457 struct sk_buff *rep_skb; 463 struct sk_buff *rep_skb;
458 void *reply; 464 void *reply;
459 size_t size; 465 size_t size;
@@ -480,20 +486,17 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
480 if (list_empty(&listeners->list)) 486 if (list_empty(&listeners->list))
481 return; 487 return;
482 488
483 tidstats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
484 if (!tidstats)
485 return;
486
487 rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, &reply, size); 489 rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, &reply, size);
488 if (rc < 0) 490 if (rc < 0)
489 goto free_stats; 491 return;
490 492
491 rc = fill_pid(tsk->pid, tsk, tidstats); 493 stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, tsk->pid);
492 if (rc < 0) 494 if (!stats)
493 goto err_skb; 495 goto nla_err;
494 496
495 if (mk_reply(rep_skb, TASKSTATS_TYPE_PID, tsk->pid, tidstats)) 497 rc = fill_pid(tsk->pid, tsk, stats);
496 goto nla_put_failure; 498 if (rc < 0)
499 goto nla_err;
497 500
498 /* 501 /*
499 * Doesn't matter if tsk is the leader or the last group member leaving 502 * Doesn't matter if tsk is the leader or the last group member leaving
@@ -501,20 +504,19 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
501 if (!is_thread_group || !group_dead) 504 if (!is_thread_group || !group_dead)
502 goto send; 505 goto send;
503 506
504 if (mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tsk->tgid, tsk->signal->stats)) 507 stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tsk->tgid);
505 goto nla_put_failure; 508 if (!stats)
509 goto nla_err;
510
511 memcpy(stats, tsk->signal->stats, sizeof(*stats));
506 512
507send: 513send:
508 send_cpu_listeners(rep_skb, listeners); 514 send_cpu_listeners(rep_skb, listeners);
509free_stats:
510 kmem_cache_free(taskstats_cache, tidstats);
511 return; 515 return;
512 516
513nla_put_failure: 517nla_err:
514 genlmsg_cancel(rep_skb, reply); 518 genlmsg_cancel(rep_skb, reply);
515err_skb:
516 nlmsg_free(rep_skb); 519 nlmsg_free(rep_skb);
517 goto free_stats;
518} 520}
519 521
520static struct genl_ops taskstats_ops = { 522static struct genl_ops taskstats_ops = {