diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2006-12-06 23:36:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 11:39:34 -0500 |
commit | 51de4d90852ba4cfa5743594ec4a7f158b52dc43 (patch) | |
tree | 27ee40313c79c3c5fa2ef86fc059cf991c92e8e2 | |
parent | 68062b86fc0f480b806d270a8278709a5a41bb67 (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.c | 86 |
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 | ||
346 | static int mk_reply(struct sk_buff *skb, int type, u32 pid, struct taskstats *stats) | 349 | static 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); |
361 | nla_put_failure: | 367 | err: |
362 | return -1; | 368 | return NULL; |
363 | } | 369 | } |
364 | 370 | ||
365 | static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info) | 371 | static 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 | ||
420 | nla_put_failure: | 426 | nla_err: |
421 | rc = genlmsg_cancel(rep_skb, reply); | 427 | genlmsg_cancel(rep_skb, reply); |
422 | err: | 428 | err: |
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 | ||
507 | send: | 513 | send: |
508 | send_cpu_listeners(rep_skb, listeners); | 514 | send_cpu_listeners(rep_skb, listeners); |
509 | free_stats: | ||
510 | kmem_cache_free(taskstats_cache, tidstats); | ||
511 | return; | 515 | return; |
512 | 516 | ||
513 | nla_put_failure: | 517 | nla_err: |
514 | genlmsg_cancel(rep_skb, reply); | 518 | genlmsg_cancel(rep_skb, reply); |
515 | err_skb: | ||
516 | nlmsg_free(rep_skb); | 519 | nlmsg_free(rep_skb); |
517 | goto free_stats; | ||
518 | } | 520 | } |
519 | 521 | ||
520 | static struct genl_ops taskstats_ops = { | 522 | static struct genl_ops taskstats_ops = { |