{
 "number": 31672,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/31672",
 "title": "rpc: add cpu_load to getpeerinfo",
 "author": "vasild",
 "author_association": "MEMBER",
 "created_at": "2025-01-16T14:02:03Z",
 "updated_at": "2026-09-11T01:06:48Z",
 "age_days": 609,
 "draft": false,
 "labels": [
  "RPC/REST/ZMQ"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "52f1efc06afe5787fdc60a190647aadbc4981981",
 "head_ref": "peer_cpu_load",
 "head_repo": "vasild/bitcoin",
 "head_history": [
  {
   "t": "2025-01-16T14:04:54Z",
   "sha": "e17fd621052c7f28055d9c483ba03e00bdd42aab"
  },
  {
   "t": "2025-01-16T17:45:18Z",
   "sha": "2a7b61eb9e24b63f107cca4a94bc7a862f216f7e"
  },
  {
   "t": "2025-01-21T13:24:35Z",
   "sha": "dc581f60a0e71232f69c294441f2e45f2991b4a3"
  },
  {
   "t": "2025-01-22T08:17:31Z",
   "sha": "3de9c9ccebb06c5c23c058697531dc6d8795794e"
  },
  {
   "t": "2025-01-22T14:01:40Z",
   "sha": "8a3ec6fcf1c4414ce83d8e78522ded9aab3bddc8"
  },
  {
   "t": "2025-01-22T17:35:43Z",
   "sha": "28b2a67f130c7f2bbc0b4ee3fee441e4d51112fc"
  },
  {
   "t": "2025-01-23T12:37:57Z",
   "sha": "0f68c47e931de05200adeae639bcee50ea3c171d"
  },
  {
   "t": "2025-04-15T08:24:43Z",
   "sha": "e374825246f1319e2cf67dbfd0cb2df0fbcff6cf"
  },
  {
   "t": "2025-04-15T08:29:10Z",
   "sha": "9cc8ca3b1fe2b20e465ddc030c21ac36570f2935"
  },
  {
   "t": "2025-04-17T07:17:58Z",
   "sha": "bb822a5ee1f94755f5b444a9a6cb5d4ab167b9bf"
  },
  {
   "t": "2025-04-17T09:33:56Z",
   "sha": "ee16345af3ad16a442a0b461b7612605d18720df"
  },
  {
   "t": "2025-04-17T10:05:34Z",
   "sha": "19c8336d970259cec2877e75c9f5c206513ffe6e"
  },
  {
   "t": "2025-05-13T13:44:50Z",
   "sha": "8b8b85434653f66a275a1f757d49a719847b57e5"
  },
  {
   "t": "2025-06-20T08:00:07Z",
   "sha": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a"
  },
  {
   "t": "2026-04-29T14:29:29Z",
   "sha": "52f1efc06afe5787fdc60a190647aadbc4981981"
  }
 ],
 "additions": 160,
 "deletions": 4,
 "changed_files": 8,
 "commit_count": 2,
 "size_bucket": "M",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "ack": [
     {
      "login": "yuvicc",
      "url": "https://github.com/bitcoin/bitcoin/pull/31672#pullrequestreview-4357940480"
     }
    ],
    "concept_nack": [
     {
      "login": "rebroad",
      "url": "https://github.com/bitcoin/bitcoin/pull/31672#issuecomment-3128696488"
     }
    ],
    "concept_ack": [
     {
      "login": "theStack",
      "url": "https://github.com/bitcoin/bitcoin/pull/31672#issuecomment-2596396995"
     },
     {
      "login": "BrandonOdiwuor",
      "url": "https://github.com/bitcoin/bitcoin/pull/31672#pullrequestreview-2557008931"
     },
     {
      "login": "laanwj",
      "url": "https://github.com/bitcoin/bitcoin/pull/31672#issuecomment-2789172534"
     },
     {
      "login": "mzumsande",
      "url": "https://github.com/bitcoin/bitcoin/pull/31672#pullrequestreview-2764699096"
     },
     {
      "login": "1440000bytes",
      "url": "https://github.com/bitcoin/bitcoin/pull/31672#issuecomment-2598860948"
     },
     {
      "login": "sipa",
      "url": "https://github.com/bitcoin/bitcoin/pull/31672#issuecomment-4546559323"
     }
    ],
    "stale_ack": [
     {
      "login": "jonatack",
      "url": "https://github.com/bitcoin/bitcoin/pull/31672#pullrequestreview-2773176971"
     }
    ]
   },
   "conflicts": [
    {
     "number": 19461,
     "title": "multiprocess: Add bitcoin-gui -ipcconnect option",
     "author": "ryanofsky"
    },
    {
     "number": 19460,
     "title": "multiprocess: Add bitcoin-wallet -ipcconnect option",
     "author": "ryanofsky"
    },
    {
     "number": 10102,
     "title": "Multiprocess bitcoin",
     "author": "ryanofsky"
    }
   ]
  }
 },
 "acks_parsed": {
  "jonatack": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2025-01-16T14:25:27Z",
   "stale": false
  },
  "sipa": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-05-26T17:01:01Z",
   "stale": false
  },
  "theStack": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2025-01-16T18:15:12Z",
   "stale": false
  },
  "BrandonOdiwuor": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2025-01-16T19:00:17Z",
   "stale": false
  },
  "1440000bytes": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2025-01-17T17:34:24Z",
   "stale": false
  },
  "yuvicc": {
   "kind": "ack",
   "hash": "52f1efc06afe5787fdc60a190647aadbc4981981",
   "t": "2026-05-25T16:53:39Z",
   "stale": false
  },
  "mzumsande": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2025-04-14T17:44:03Z",
   "stale": false
  },
  "rebroad": {
   "kind": "nack",
   "hash": null,
   "t": "2025-07-28T19:06:27Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 1,
  "stale_ack": 0,
  "concept_ack": 6,
  "approach_ack": 0,
  "nack": 1,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 1,
  "changes_requested": 0,
  "distinct_reviewers": [
   "0xB10C",
   "1440000bytes",
   "BrandonOdiwuor",
   "ajtowns",
   "fanquake",
   "jonatack",
   "laanwj",
   "luke-jr",
   "maflcko",
   "mzumsande",
   "rebroad",
   "sedited",
   "sipa",
   "theStack",
   "yuvicc"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-04-29T14:36:01Z",
  "last_reviewer_activity": "2026-08-21T06:40:21Z",
  "last_reviewer": "BrandonOdiwuor",
  "author_silent_days": 141,
  "waiting_on_author_days": 27,
  "days_since_update": 6
 },
 "refs": {
  "mentioned": [
   31033
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 31033,
    "type": "issue",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "Prioritize processing of peers based on their CPU usage"
   }
  ],
  "conflicts": [
   19461,
   19460,
   10102
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "cmake/introspection.cmake",
  "doc/release-notes-31672.md",
  "src/rpc/net.cpp",
  "src/util/time.cpp"
 ],
 "body": "Add a new field `cpu_load` to the output of `getpeerinfo` RPC.\n\nIt represents the CPU time spent by the message handling thread for the given peer, weighted for the duration of the connection. That is, for example, if two peers are equally demanding and one is connected longer than the other, then they will have the same `cpu_load` number.\n\n---\n\nMonitoring CPU usage is useful on its own. Also related to https://github.com/bitcoin/bitcoin/issues/31033.\n\n---\n\nThis PR uses `clock_gettime()` (POSIX) and `GetThreadTimes()` (Windows). An alternative to those, should this be explored are: `getrusage()` (POSIX) and `QueryThreadCycleTime()` (Windows, but it counts CPU cycles).",
 "commits": [
  {
   "sha": "cb2eab91188ecb87b3dae9ff3cf71db1918d9594",
   "date": "2026-04-29T14:11:35Z",
   "message": "rpc: add cpu_load to getpeerinfo\n\nAdd a new field `cpu_load` to the output of `getpeerinfo` RPC.\n\nIt represents the CPU time spent by the message handling thread for the\ngiven peer, weighted for the duration of the connection. That is, for\nexample, if two peers are equally demanding and one is connected longer\nthan the other, then they will have the same `cpu_load` number."
  },
  {
   "sha": "52f1efc06afe5787fdc60a190647aadbc4981981",
   "date": "2026-04-29T14:11:37Z",
   "message": "cli: add getpeerinfo#cpu_load to -netinfo"
  }
 ],
 "timeline": [
  {
   "t": "2025-01-16T14:04:54Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "e17fd621052c7f28055d9c483ba03e00bdd42aab"
  },
  {
   "t": "2025-01-16T14:25:27Z",
   "kind": "comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "text": "Concept ACK if this can be a reliable, useful metric and help pave the path to https://github.com/bitcoin/bitcoin/issues/31033."
  },
  {
   "t": "2025-01-16T15:24:20Z",
   "kind": "comment",
   "who": "sipa",
   "assoc": "MEMBER",
   "text": "Concept ACK"
  },
  {
   "t": "2025-01-16T17:45:18Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "2a7b61eb9e24b63f107cca4a94bc7a862f216f7e"
  },
  {
   "t": "2025-01-16T18:15:12Z",
   "kind": "comment",
   "who": "theStack",
   "assoc": "MEMBER",
   "text": "Concept ACK\n\nMight be worth noting that this is currently only available on POSIX systems (i.e. not available on Windows, but on all other systems that we support AFAICT) in both the RPC help and a release note."
  },
  {
   "t": "2025-01-16T19:00:17Z",
   "kind": "review",
   "who": "BrandonOdiwuor",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "2a7b61eb9e24b63f107cca4a94bc7a862f216f7e",
   "text": "Concept ACK"
  },
  {
   "t": "2025-01-17T13:06:41Z",
   "kind": "comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "text": "Seems like there was some very brief discussion in #31033, and the conclusion [\"I guess this should start with planting some metrics\"](https://github.com/bitcoin/bitcoin/issues/31033#issuecomment-2394932171), but I'm not sure putting changes into Bitcoin Core is the right first step.\n\nBefore changing our API, it'd be good to atleast show some usage that indicates that the changes here are useful. I assume you've already been running this locally, and collecting the data, so it'd be good to know what it turned up?\n\nAs noted in #31033, others have also already conducted similar research (https://b10c.me/projects/023-cpu-usage-of-peers/ or https://delvingbitcoin.org/t/cpu-usage-of-peers/196), and it seems like the data you'd expose here, will be less detailed / useful than what can/has already been produced using tracepoints or similar, so I'm wondering if this is the best approach."
  },
  {
   "t": "2025-01-17T16:44:02Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "@fanquake IMO, monitoring CPU usage is useful on its own, even if we don't start treating peers differently based on that metric (https://github.com/bitcoin/bitcoin/issues/31033). In other words, this metric is useful at least as much as a bunch of other metrics in the `getpeerinfo` output.\n\nYes, I have been running this locally - there is like 65x difference between the least and most demanding peers. I am curious to correlate this to the messages being sent/received to/from those peers and to have a histogram of the data, not just least / most demanding (e.g. histogram of `bitcoin-cli getpeerinfo |jq \".[].cpu_load\"`). I view those as something nice to build on top of this PR, not as a blocker that's needed to justify the usefulness of the CPU time metric."
  },
  {
   "t": "2025-01-17T17:34:24Z",
   "kind": "comment",
   "who": "1440000bytes",
   "assoc": "CONTRIBUTOR",
   "text": "Concept ACK"
  },
  {
   "t": "2025-01-20T12:25:24Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nRight. [`GetThreadTimes()`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes) looks like a promising Windows alternative. I will try to implement that here. Switching to draft because I will push some work-in-progress a bunch of times."
  },
  {
   "t": "2025-01-21T13:24:35Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "dc581f60a0e71232f69c294441f2e45f2991b4a3"
  },
  {
   "t": "2025-01-22T08:17:31Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "3de9c9ccebb06c5c23c058697531dc6d8795794e"
  },
  {
   "t": "2025-01-22T14:01:40Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "8a3ec6fcf1c4414ce83d8e78522ded9aab3bddc8"
  },
  {
   "t": "2025-01-22T17:35:43Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "28b2a67f130c7f2bbc0b4ee3fee441e4d51112fc"
  },
  {
   "t": "2025-01-23T10:07:11Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "Ready for review. Implemented for Windows as well.\n\nHere is a [test program](https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1DIApACYAQuYukl9ZATwDKjdAGFUtAK4sGEgJykrgAyeAyYAHI%2BAEaYxCDSAA6oCoRODB7evgGkyamOAqHhUSyx8dJ2mA7pQgRMxASZPn5cgZXVArX1BEWRMXEJtnUNTdmtQ929JWUJAJS2qF7EyOwc5gDMYcjeWADUJutuTApKDQB0CAfYJhoAgjf3ZpsM2157B24A7mHoqJ8KFyuDw2Wx2mH2h2%2BDEEgPW1zuwKeoLe4I%2BiWIqBWJwICGImCY6AUTESeFh8PuCKRLzBELcTgUBDxrCBlOer3ehxxTPQLIptwAbqg8Ohdlz8egIKkAF6YAD6BF2nxIAGtZsCAOxWO67HW7ABiAElgtgACoGgCy2F2sX4eNlyCZBQYBy1t11%2BqNpotVptJDlmFUhBdD3dhuNZst1swtrlyri4Vowe1urDXsjvrtXlOSbduuiqE8uzxCoOABFdgBxTAEE248UmvBsBQQKuNJZ4wS17kQeYh9268wANgzcod%2BKdpD7/f2ZmH0b9soDhEnyenQ5HsrjxATK9za9nG6zcTV61d7uOpwIEGLENLZd2XBPrqnuzwVF2ECVxGVEKtXA0YAcBowGzPsmovu6toftKcoKngJiahoCF3qer60oqKoujOViWHgoEIWe079hAgrCrMEB4LsABUr5PhBA7qneq5geWmC0EoYGEdODLoCAIA4ngCjynWBJ8Qo9CYIksq2pKBC8SguICKgfEsHQtCCVUAiEgRX7KshdHMchwLMamEZWkwVAEHE9qOukOahp6Zm7BZVnEIugYEPZKaOd6zmWdZW4Jl5Oqmb5LnWUexDBUW1a3pW1ZdvWjaYM2rZuO2jA1iJEq9sx7pDuFbljkwE70TqBX%2BW5S4ELuREzoOhWbvGbG1URFWubKkUGXuzknHEV43mW96PjmL5yMEtwAEoVtgsoGhEJrYDNk1RjGTXbmxsrRRugWbWcwR/Mo3RxTtzW0Gc6CfAdnyliVmANmw23znau20LKZwABJ4MACBHQ0J3PbGZ0XZ8X0/bdVkPZgo3MeNU0zXNC1LdgK2HqcW2ni%2BaPWfth3Hfe2PECD10Q/dyVPWtkXvWDv34%2Bs5aEyDNOk1DMM9XD02zfNi3LX5HWvRjXF8wFZ3vddf0lvTwtua9xN/Cz5OY8xjUC59320/994q8Dl3M3drNK3y7ocwj3PIytjVU9Flvo7jnwS3FNtxHLN364rQtO25as/Q7WuVZ1pxM%2BrCuPYbY0TZziM8yjuxscSSg8ob7px4kCdnAAil4BK%2B1L2sbW9GdZ%2BgvuWNLAc45n2fHQAtKtC6q5Xxc13Xma243EvReNADyEQVsEPcVrHBip5g6CygwCgESnaft8dNH/khjHRTxfFoF4ktuB8M5mMgiReKKyUgNvtJb9Po/jwouwAPQPoBwEAUBwF38BZwaCfhzH0opgAKxuM6ZhmFGkvBEdwwgKhYEwMIH41QInAsxFe/Fsqii4ARMUBJSAPnvlg4CRkk66gQWgkUBBAGakIRghe2CcFLzwTqAhSCCDrFQdlDB6x764KFgQLgZxtBCgYD2aKxDuG8P4TQ0U6whFhBEc%2BZixYlgMF2EhMOjEODzFoJwb%2BvA/BAV4MpDgm9LDWF2AoRYyxURPB4KQAgmgVHzGVCAdUGgzgAA5ZySEkIOMwTiND%2BH8FwdUg59CcEkJo6xpBdG8AUCADQljrHzDgLAJAAYqjrxIOQSg9RgAKCOgmIQCA/haIsWgFgJIDBOmyWxXJ%2BTQlFJKQMfku8pL8laLKUpKUCCylUIOaQNS6BxAiKwVYvAen0GIF3delTPhaK0EEVQVRbjEEyZwXgSTkC1HwFo3g/BBAiDEOwf8MhBCKBUOobRpBdBmH0IYYw1hrD6DwNESJkB5ioESE6SJHAr4r1MAYywZhpmoH5HEYgwoUrwHmMQLwghkomgLOxMFCwlgrD0DxMI5TaATKmbwRkmBVgWM%2BMQYksTAkcA0aQTFYTODYFmcgFJxBdidMkLsFgCh6m7Caf4M4rSGQfn0ThGwuxcCEBIDOdYj4sWxPmAgcUAweykDsWYDlfj1jf2/usdUrRgIuMHE44lwTSAsAkMBMloTwm2CiTE7RsxVGcDMCE05pqrGWvmIC4gqRnCSCAA%3D) I played with to test this manually. I think it is not worth adding as a unit test or benchmark, but at least it can live here in the comments of this PR:\n\ncpu_time_windows.cpp\n\n```cpp\n#include <assert.h>\n\n#include <windows.h>\n#include <winnt.h>\n\n#include <processthreadsapi.h>\n\n#include <iostream>\n#include <thread>\n\nvoid thread(size_t work)\n{\n    FILETIME before_creation;\n    FILETIME before_exit;\n    FILETIME before_kernel;\n    FILETIME before_user;\n    bool ret = GetThreadTimes(GetCurrentThread(),\n        &before_creation,\n        &before_exit,\n        &before_kernel,\n        &before_user);\n    assert(ret == 1);\n\n    if (work > 10'000) {\n        for (size_t i{0}; i < work; ++i) {\n            (void)(i * i);\n        }\n    } else {\n        std::this_thread::sleep_for(std::chrono::milliseconds{work});\n    }\n\n    FILETIME after_creation;\n    FILETIME after_exit;\n    FILETIME after_kernel;\n    FILETIME after_user;\n    ret = GetThreadTimes(GetCurrentThread(),\n        &after_creation,\n        &after_exit,\n        &after_kernel,\n        &after_user);\n    assert(ret == 1);\n\n    ULARGE_INTEGER before_kernel_;\n    before_kernel_.LowPart = before_kernel.dwLowDateTime;\n    before_kernel_.HighPart = before_kernel.dwHighDateTime;\n\n    ULARGE_INTEGER before_user_;\n    before_user_.LowPart = before_user.dwLowDateTime;\n    before_user_.HighPart = before_user.dwHighDateTime;\n\n    ULARGE_INTEGER after_kernel_;\n    after_kernel_.LowPart = after_kernel.dwLowDateTime;\n    after_kernel_.HighPart = after_kernel.dwHighDateTime;\n\n    ULARGE_INTEGER after_user_;\n    after_user_.LowPart = after_user.dwLowDateTime;\n    after_user_.HighPart = after_user.dwHighDateTime;\n\n    ULARGE_INTEGER elapsed;\n    elapsed.QuadPart = after_kernel_.QuadPart + after_user_.QuadPart - before_kernel_.QuadPart - before_user_.QuadPart;\n    ULONGLONG elapsed_ns{elapsed.QuadPart * 100};\n    std::cout << \"cpu time: \" << elapsed_ns / 1'000'000'000.0 << \" sec\\n\";\n}\n\nint main ()\n{\n    std::thread t1{thread, 1000000000};\n    std::thread t2{thread, 1000000000};\n    std::thread t3{thread, 3000};\n    t1.join();\n    t2.join();\n    t3.join();\n\n    return 0;\n}\n```"
  },
  {
   "t": "2025-01-23T10:19:13Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/rpc/net.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "Currently I chose to represent the CPU load as 1/1000s of the connection time. For example, if we have spent 5 CPU seconds for a peer that has been connected for 1000 seconds, then `cpu_load` will be 5.\n\nOutput of `bitcoin-cli getpeerinfo |jq '.[].cpu_load ' |sort -n`:\n\n* Shortly after startup:\n```\n0.003207936170212766\n0.003909962962962963\n0.004000127659574468\n0.004340326086956522\n0.00904279365079365\n0.0270041914893617\n0.03776429787234042\n0.04154987234042553\n0.05750733333333333\n0.0828310843373494\n0.1014558936170213\n0.1453753214285714\n0.1619409404761905\n```\n\n* After running for a few hours:\n```\n0.5100616477272727\n0.7087315352941177\n0.7814365649717514\n0.8773131578947369\n0.9717403481228669\n1.069695995623632\n1.078479046189377\n1.153550253945481\n1.167638256213824\n1.187242140449438\n1.199645694868011\n1.199951082706767\n1.220689207655502\n1.264582222222222\n1.265083146221971\n1.282676876955162\n1.301380197644649\n1.303624877378436\n1.333201868001821\n1.341489760490639\n1.343411334541063\n1.361829386934673\n1.364938446935725\n1.372325493506493\n1.385421828947368\n1.472354355769231\n1.612321964879852\n1.641998848148148\n1.648207868421053\n1.681837521410579\n1.783343262569832\n1.78646682029841\n1.837577241385135\n1.844571151379764\n1.851067047263682\n1.908551290322581\n1.915087061408061\n1.923511220435511\n1.939589383639822\n1.940788162162162\n1.962705583687341\n2.000298126030624\n2.008423324931507\n2.00921122707588\n2.018911893157895\n2.019168323205742\n2.019358503865546\n2.030658536117768\n2.034708427345187\n2.03510252110758\n2.04022746739726\n2.054511708699122\n2.07339420882353\n2.076240002244949\n2.080369749066667\n2.08561637254902\n2.092916448969578\n2.095147154892331\n2.119004164227642\n2.129640033722438\n2.145774200383772\n2.164519192393115\n2.27069154817898\n2.29444800067659\n2.313547881255947\n2.31539280930693\n2.368903822619457\n2.445622954545454\n2.503377741525424\n2.557022695182724\n2.56755574523507\n2.709643024574987\n2.724320047021944\n2.913325884282384\n3.154521111713488\n3.706281482599432\n3.843126643942505\n3.865110431762718\n3.934123987370194\n4.634227207136824\n5.185085595879828\n5.233027217613057\n5.766649107296137\n6.105655600034141\n6.138089870962286\n10.09238865432725\n10.24402739230769\n10.56650271556122\n20.75054951145038\n47.69228849275363\n77.79810328289474\n145.2686368960396\n```\n\nMaybe using an integer would be better for this? Then it would have to have higher resolution, e.g. instead of 1/1000s it should show 1/1Bs? Then the above numbers would vary from 3207 to 145'268'636. E.g. the lightest peer has caused 3207 nanoseconds of CPU time for each 1 second (=1B nanoseconds) of connection time."
  },
  {
   "t": "2025-01-23T10:25:55Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/time.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "nit: Instead of manual casting and multiplication, you can use chrono types and let the compiler insert what is needed."
  },
  {
   "t": "2025-01-23T10:29:24Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/rpc/net.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "nit: Instead of manually casting, you can just divide two chrono types and let the compiler insert anything that is needed."
  },
  {
   "t": "2025-01-23T10:31:15Z",
   "kind": "review",
   "who": "maflcko",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "28b2a67f130c7f2bbc0b4ee3fee441e4d51112fc",
   "text": "(left two nits, feel free to ignore)"
  },
  {
   "t": "2025-01-23T12:37:57Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "0f68c47e931de05200adeae639bcee50ea3c171d"
  },
  {
   "t": "2025-01-23T12:38:25Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "`28b2a67f13...0f68c47e93`: address suggestions by @maflcko"
  },
  {
   "t": "2025-01-23T12:38:54Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/util/time.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 1926735815,
   "text": "Right, much better and simpler this way. Thanks!"
  },
  {
   "t": "2025-01-23T12:40:34Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/rpc/net.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 1926740913,
   "text": "Thanks for the suggestion! And now no need to add a new function `count_nanoseconds()`."
  },
  {
   "t": "2025-01-23T13:06:19Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "The code here assumes that Bitcoin Core is single threaded, which may be true right now, but could change in the future."
  },
  {
   "t": "2025-01-25T20:35:23Z",
   "kind": "comment",
   "who": "luke-jr",
   "assoc": "CONTRIBUTOR",
   "text": "How so? Both implementations use thread-specific timers...?"
  },
  {
   "t": "2025-01-26T16:40:11Z",
   "kind": "comment",
   "who": "yuvicc",
   "assoc": "CONTRIBUTOR",
   "text": "Concept ACK\n\nI think this would be a clean way to get peers' CPU usage for message processing since Tracepoints is currently not compatible with macOS/Windows for which folks will be having a hard time.\n\nAlso, this could pave the way for prioritising peers based on CPU usage #31033."
  },
  {
   "t": "2025-01-26T16:52:55Z",
   "kind": "comment",
   "who": "yuvicc",
   "assoc": "CONTRIBUTOR",
   "text": "Also, during my observations I found value `null` as well.\n\n```\nnull\n0.0352094358974359\n0.54925525\n0.579001\n0.6585706\n1.390154842105263\n1.703986581081081\n2.427459408450704\n24.85140159887005\n```\nAny idea why is it null? maybe it is about to get disconnected."
  },
  {
   "t": "2025-01-27T10:52:34Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\n`jq '.[].cpu_load'` displays `null` when there is no `cpu_load` in the JSON for that peer. The new field is optional:\n\n```\n$ bitcoin-cli help getpeerinfo\n...\n    \"cpu_load\" : n,                       (numeric, optional) The CPU time (user + system) spent processing messages from this peer and crafting messages for it expressed in per milles (\u2030) of the duration of the connection. Will be omitted on platforms that do not support this or if still not measured.\n```\n\nThe omission comes from this condition:\n\n```cpp\nif (stats.m_cpu_time > 0s && now > stats.m_connected) {\n```\n\nWithin 1 second of connecting, `now` will be equal to `stats.m_connected` (they use second-precision). I am open to suggestions if you think this can be done in a better or more intuitive way."
  },
  {
   "t": "2025-01-27T11:01:02Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nHmm? https://github.com/bitcoin/bitcoin/blob/0a931a9787b196d7a620863cc143d9319ffd356d/doc/developer-notes.md#threads\n\n[quoted text omitted]\nI guess you mean that message processing is single threaded - the `b-msghand` thread. I agree it could change in the future."
  },
  {
   "t": "2025-01-27T12:46:21Z",
   "kind": "comment",
   "who": "yuvicc",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nGot it, thanks!"
  },
  {
   "t": "2025-01-27T12:49:26Z",
   "kind": "review",
   "who": "yuvicc",
   "assoc": "CONTRIBUTOR",
   "state": "APPROVED",
   "commit": "0f68c47e931de05200adeae639bcee50ea3c171d",
   "text": "tACK 0f68c47e931de05200adeae639bcee50ea3c171d"
  },
  {
   "t": "2025-02-05T11:26:47Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nI left the comment, because if the work is done in a different thread, this feature will silently break. I guess that is fine if the work is minimal, or code could be added to do the additional accounting if the work is substantial."
  },
  {
   "t": "2025-02-05T12:29:34Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "@maflcko yes, I agree. Future changes that make message processing multi-threaded will have to take this into account."
  },
  {
   "t": "2025-04-09T10:18:54Z",
   "kind": "comment",
   "who": "laanwj",
   "assoc": "MEMBER",
   "text": "Ohh this is neat. Concept ACK.\n\n[quoted text omitted]\nWhere i think monitoring per-peer CPU usage is most concretely useful is for anti-DoS measures. Reporting it is a (still useful) first step.\n\n(do agree tracepoint are much better for gathering detailed information, but there's internal applications of this)"
  },
  {
   "t": "2025-04-09T15:47:52Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "Hmm, https://b10c.me/projects/023-cpu-usage-of-peers/ and https://github.com/0xB10C/bitcoin/commit/59c0fe438a3e62d27eda237ae20c062608e047b3 measure the real time, aka wall clock time (cc @0xB10C).\n\nMessage processing is single threaded, which means that we do not process messages from more than one peer at a given time, but still there are other threads in `bitcoind` and other processes on the system which influence the \"real time\". That is, `bitcoind` may perform identical tasks for two peers, but while doing the tasks for the second peer some other thread or process hogs the system and delays the completion. This will skew the results.\n\nTo measure properly one has to measure \"CPU time\", not \"real time\". It can still be done with tracepoints, but the CPU measuring function from this PR would have to be used."
  },
  {
   "t": "2025-04-09T17:23:21Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "I wouldn't say that one metric is more proper than the other one. Some people run on slow IO devices, so measuring the wall clock time is reasonable to find peers that  eat CPU or IO (or both). Of course wall-clock is more fragile and it means you can't hammer the program over RPC at the same time, or do anything else on the whole system, but it is still a valid way to measure. (See also the recent commit to perf that added wall-clock measurements: https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=32ecca8d7a3e2400805f8b5564a1b07e05cfcd54)"
  },
  {
   "t": "2025-04-14T15:09:43Z",
   "kind": "review_comment",
   "who": "mzumsande",
   "assoc": "MEMBER",
   "path": "doc/release-notes-31672.md",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "nit: `not yet measured` sounds more correct to me."
  },
  {
   "t": "2025-04-14T17:44:03Z",
   "kind": "review",
   "who": "mzumsande",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "0f68c47e931de05200adeae639bcee50ea3c171d",
   "text": "Concept ACK, but I think that the `cpu_load` is not straightforward to interpret.\n\nAs I wrote in https://github.com/bitcoin/bitcoin/issues/31033#issuecomment-2802145335 I'd say that in absence of an attack, the highest CPU load peers are our most useful ones - it would be a unfortunate if users attempted to disconnect \"DoSy\" their peers based on this statistics when there is no actual DoS situation.\n\nOn the other hand, I think that this would be really useful in case of an actual attack. If users see their node becoming slow, `cpu_load` could help detect who the attacker is and what they are doing."
  },
  {
   "t": "2025-04-15T08:24:43Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "e374825246f1319e2cf67dbfd0cb2df0fbcff6cf"
  },
  {
   "t": "2025-04-15T08:25:07Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "`0f68c47e93...e374825246`: address suggestion"
  },
  {
   "t": "2025-04-15T08:29:10Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "9cc8ca3b1fe2b20e465ddc030c21ac36570f2935"
  },
  {
   "t": "2025-04-15T08:29:58Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "doc/release-notes-31672.md",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2042356503,
   "text": "Done. Also elaborated a little bit the help text."
  },
  {
   "t": "2025-04-15T08:30:35Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "`e374825246...9cc8ca3b1f`: also update `getpeerinfo` help"
  },
  {
   "t": "2025-04-16T16:36:45Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "doc/release-notes-31672.md",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "```suggestion\nhigh CPU time is not necessarily a bad thing - new valid transactions and\n```"
  },
  {
   "t": "2025-04-16T17:53:09Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "doc/release-notes-31672.md",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "maybe more simply replace \"processing messages from the given peer and crafting messages for it\" with \"processing messages to/from the peer\"\n\n(same for the RPC help)"
  },
  {
   "t": "2025-04-16T17:57:58Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/rpc/net.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "nit, this is very long\n\n```\n    \"bytesrecv\" : n,                      (numeric) The total bytes received\n    \"cpu_load\" : n,                       (numeric, optional) The CPU time (user + system) spent processing messages from this peer and crafting messages for it expressed in per milles (\u2030) of the duration of the connection. Will be omitted on platforms that do not support this or if still not measured. Note that high CPU time is not necessary a bad thing - new, valid, transactions and blocks require CPU time to be validated.\n    \"conntime\" : xxx,                     (numeric) The UNIX epoch time of the connection\n```\n\nperhaps more simply:\n\n\"The CPU time (user + system) spent processing messages to/from the peer, in per milles (\u2030) of the connection duration\""
  },
  {
   "t": "2025-04-16T18:05:52Z",
   "kind": "review",
   "who": "jonatack",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "9cc8ca3b1fe2b20e465ddc030c21ac36570f2935",
   "text": "Light initial tested ACK 9cc8ca3b1fe2b20e465ddc030c21ac36570f2935\n\nI did not review the cmake build code.\n\nTested RPC getpeerinfo and have also been testing this by running the following branch https://github.com/jonatack/bitcoin/commits/2025-04-add-cpu_load-to-netinfo/ containing an additional commit, and then running a live dashboard with\n\n```\n$ watch ./build/bin/bitcoin-cli -rpcwait -netinfo 4\n```"
  },
  {
   "t": "2025-04-16T21:29:10Z",
   "kind": "review",
   "who": "yuvicc",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "9cc8ca3b1fe2b20e465ddc030c21ac36570f2935",
   "text": "ACK 9cc8ca3b1fe2b20e465ddc030c21ac36570f2935"
  },
  {
   "t": "2025-04-17T07:17:58Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "bb822a5ee1f94755f5b444a9a6cb5d4ab167b9bf"
  },
  {
   "t": "2025-04-17T07:21:11Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "`9cc8ca3b1f...bb822a5ee1`: address suggestions\n\nI think the `bitcoin-cli` extension in https://github.com/jonatack/bitcoin/commit/708a9502f8eca7aaa84236ea038a574f4350f298#r155516952 might be included in this PR. @i-am-yuvi, since you ACKed this PR without that extra commit, what do you think? Should it be included?"
  },
  {
   "t": "2025-04-17T07:21:25Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "doc/release-notes-31672.md",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2047324760,
   "text": "Done."
  },
  {
   "t": "2025-04-17T07:21:40Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "doc/release-notes-31672.md",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2047441494,
   "text": "Done."
  },
  {
   "t": "2025-04-17T07:24:03Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/rpc/net.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2047449588,
   "text": "Shortened a bit but not that much since this is the only help text (I assume release notes are not so useful for somebody looking into this for the first time in e.g. version 35.0, they will not go to search for past release notes).\n\nOther help texts include `\\n`, maybe do that here as well?"
  },
  {
   "t": "2025-04-17T09:09:07Z",
   "kind": "review_comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "path": "cmake/introspection.cmake",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "I don't think we need to introduce checks here, we already use `clock_gettime`. You could just #ifdef `CLOCK_THREAD_CPUTIME_ID` at the callsite."
  },
  {
   "t": "2025-04-17T09:09:59Z",
   "kind": "review_comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "path": "cmake/introspection.cmake",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "I don't think we check for any other Windows functions like this, I think you can just #ifdef WIN32 at the callsite."
  },
  {
   "t": "2025-04-17T09:10:29Z",
   "kind": "review_comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "path": "src/util/time.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "If you're going to link to external documentation, there's no need to copy paragraphs of it, verbatim, into our source code."
  },
  {
   "t": "2025-04-17T09:11:02Z",
   "kind": "review_comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "path": "src/util/time.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "Comment seems unnecessary?"
  },
  {
   "t": "2025-04-17T09:33:56Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "ee16345af3ad16a442a0b461b7612605d18720df"
  },
  {
   "t": "2025-04-17T09:34:14Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "`bb822a5ee1...ee16345af3`: address suggestions"
  },
  {
   "t": "2025-04-17T09:34:28Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "cmake/introspection.cmake",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2048555899,
   "text": "Done."
  },
  {
   "t": "2025-04-17T09:34:57Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "cmake/introspection.cmake",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2048557177,
   "text": "Done. This removes all build system changes from this PR, thanks!"
  },
  {
   "t": "2025-04-17T09:35:13Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/util/time.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2048558857,
   "text": "Removed."
  },
  {
   "t": "2025-04-17T09:37:44Z",
   "kind": "review_comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "path": "src/util/time.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": null,
   "text": "Same here, as the `clock_gettime` alternative comment."
  },
  {
   "t": "2025-04-17T09:37:58Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/util/time.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2048557940,
   "text": "The linked article is long and convoluted and here I want to highlight only a short part of it that is relevant. Also having the text here is helpful if the web page disappears in the future."
  },
  {
   "t": "2025-04-17T09:41:24Z",
   "kind": "review_comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "path": "src/util/time.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2048557940,
   "text": "Then I'd suggest atleast trying to consolidate what is here, given you already link to the same place above, with just \"GetThreadTimes():\" as a comment (that seems unecessary)."
  },
  {
   "t": "2025-04-17T10:05:34Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "19c8336d970259cec2877e75c9f5c206513ffe6e"
  },
  {
   "t": "2025-04-17T10:05:44Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "`ee16345af3...19c8336d97`: address suggestions"
  },
  {
   "t": "2025-04-17T10:06:35Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/util/time.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2048557940,
   "text": "Reduced the text and removed the link to the doc since it is already a few lines earlier."
  },
  {
   "t": "2025-04-17T10:07:25Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/util/time.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2048601918,
   "text": "Removed and added a note to the PR description about the alternatives."
  },
  {
   "t": "2025-04-18T21:19:40Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/rpc/net.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2047449588,
   "text": "[quoted text omitted]\n\nI'm agnostic as to that.\n\nA few text compaction ideas, feel free to pick/choose/ignore:\n\ns/The CPU time (user + system)/Total CPU time/\n\ns/spent processing/processing/\n\ns/duration. Will be omitted on platforms that do not support this or if still not measured./duration, if supported by the platform and measured./\n\ns/Note that high CPU time is not necessarily a bad thing - new valid transactions and blocks require CPU time to be validated./High CPU time is not necessarily bad; validating new transactions and blocks requires it./"
  },
  {
   "t": "2025-04-19T18:57:36Z",
   "kind": "comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "text": "Latest changes since my last review LGTM. I plan to review the code more closely.\n\nEmpirically, running a node on this branch, it looks like over time most peers settle into less than 0.5 per milles, a few are higher, with maybe one peer around 4. These higher-load connections seem to more often be outbound ones.\n\n(Edit, updated the branch with the -netinfo commit with a few improvements and to also only display cpu load for a peer (rounded to nearest integer) if it is non-zero (e.g. >= 0.5 in getpeerinfo), to more easily see which peers are using more CPU: https://github.com/jonatack/bitcoin/commits/2025-04-add-cpu_load-to-netinfo/\n\nExample 1\n\nExample 2 (a couple weeks later)"
  },
  {
   "t": "2025-05-13T13:44:50Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "8b8b85434653f66a275a1f757d49a719847b57e5"
  },
  {
   "t": "2025-05-13T13:45:38Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "`19c8336d97...8b8b854346`: address suggestions and take the `bitcoin-cli` change from https://github.com/jonatack/bitcoin/commits/2025-04-add-cpu_load-to-netinfo/, thanks!"
  },
  {
   "t": "2025-05-13T13:48:30Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/rpc/net.cpp",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a",
   "in_reply_to": 2047449588,
   "text": "Took some, thanks!"
  },
  {
   "t": "2025-06-20T08:00:07Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a"
  },
  {
   "t": "2025-06-20T08:00:35Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "`8b8b854346...b25b40ebd5`: rebase and pet tidy: `time.h` -> `ctime`"
  },
  {
   "t": "2025-07-28T19:06:27Z",
   "kind": "comment",
   "who": "rebroad",
   "assoc": "CONTRIBUTOR",
   "text": "NACK. cpu load alone is a useless metric. However, CPU load divided by TXs accepted into the chain (or mempool) could be a useful metric."
  },
  {
   "t": "2025-10-29T19:05:53Z",
   "kind": "review_comment",
   "who": "ajtowns",
   "assoc": "MEMBER",
   "path": "doc/release-notes-31672.md",
   "commit": "52f1efc06afe5787fdc60a190647aadbc4981981",
   "in_reply_to": null,
   "text": "Why monitor cpu time rather than real time? Isn't time spent waiting for disk access while looking up the utxo set equally problematic? Waiting on another thread's lock is arguably less problematic (it's the other thread that's delaying things), but if an attacker is deliberately triggering lock contention somehow to delay processing other thread's messages, that would still be a problem.\n\nAdding OS-specific logic rather than just using either real time or a steady clock seems over-complicated here.\n\n[EDIT: I guess in the context of rate-limiting expensive peers, it would be better to have a rolling average of time used for each peer, so that having sent expensive txs five hours ago has ~0 impact on how much cpu time you're getting now]"
  },
  {
   "t": "2026-01-26T15:28:50Z",
   "kind": "comment",
   "who": "0xB10C",
   "assoc": "MEMBER",
   "text": "fwiw I've been running a node with this patch for a while. Here a some numbers on min/max/mean/median I collected. I'm not sure  yet how useful these metrics are from a monitoring standpoint.\n\n---\n\nI also briefly looked into which peers have a higher `cpu_load` by `connection_type` and by `subver` by looking at a `getpeerinfo` snapshot:\n\nGenerally, connections that we relay transactions to have a higher cpu_load. Possibly because they also relay transactions to us ( A few outliners are spy-nodes (`bitnodes.earn.com`, `kit.dsn`, ..) that we relay transactions to, but don't get any from us. See chart below)."
  },
  {
   "t": "2026-04-29T13:56:42Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "doc/release-notes-31672.md",
   "commit": "52f1efc06afe5787fdc60a190647aadbc4981981",
   "in_reply_to": 2474923790,
   "text": "[quoted text omitted]\n\nBecause CPU time we know is spent only for this peer. Is the machine further spending other time for this peer? Yes. But that is no reason to not measure CPU time.\n\nReal time, on the other hand depends on _other_ tasks. Like, it might be high because the user launched Photoshop at the same time on his computer. Or because _other peers_ within the Bitcoin Core process are hogging the machine for everybody.\n\n[quoted text omitted]\nYes, it is equally or similarly problematic. If possible that should be measured as well - \"time spent on IO because of this peer\"."
  },
  {
   "t": "2026-04-29T14:29:29Z",
   "kind": "force_push",
   "who": "vasild",
   "commit": "52f1efc06afe5787fdc60a190647aadbc4981981"
  },
  {
   "t": "2026-04-29T14:36:01Z",
   "kind": "comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "text": "`b25b40ebd5ffbb5ae5cb0435aeecefdc86fc372a...52f1efc06afe5787fdc60a190647aadbc4981981`: rebase due to conflicts\n\n[quoted text omitted]\nI think this is still relevant and would be an interesting metric to have.\n\n@rebroad\n\n[quoted text omitted]\nI agree that would be useful. But for this we need the CPU load. \"TXs accepted\", if possible, can be added separately.\n\nLooking at @0xB10C's subver/cpu_load chart above - there is one outlier with unusually high cpu_load - the 3rd line `/Satoshi:29.2.0/Knots:20251110/`, hmm..."
  },
  {
   "t": "2026-05-02T20:19:25Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "Ping for @ajtowns , @sipa, @theStack, and other previous reviewers to take another look here."
  },
  {
   "t": "2026-05-25T16:53:39Z",
   "kind": "review",
   "who": "yuvicc",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "52f1efc06afe5787fdc60a190647aadbc4981981",
   "text": "Code-review ACK 52f1efc06afe5787fdc60a190647aadbc4981981\n\nCode looks good to me. Also, tested on macos to see if it reported correctly."
  },
  {
   "t": "2026-05-26T17:01:01Z",
   "kind": "comment",
   "who": "sipa",
   "assoc": "MEMBER",
   "text": "Concept ACK. I see this as exploratory work in starting monitoring of resource consumption users cause us, not as a useful metric directly.\n\nI'm not sure about making it part of the \"production\" RPC `getpeerinfo` however. I think this is work that will possibly need multiple iterations to come up with something that helps us make automated decisions (which, I think, should be the overarching goal here). For example, there may be reasons to use both CPU time (actual computation) and real time (the latency that one node causes us regardless of how)  may matter. We may want to incorporate things like work done on other threads (including script checks) if they're blocking. We may want to also keep track of things like how much we benefit (e.g. accepting blocks and transactions from  peer) at the same time, and allowing \"useful\" peers to cause us more work too. In any case, we may want to make things more granular than direct measurement (e.g. in tx orphan handling, work may be done in the context of the peer that gives us the resolving parent, even though it's for an orphan received from another peer). For all these reasons, I think it may be better to create an explicitly experimental \"resource usage dump info\" RPC than aggregating it in a `getpeerinfo` number.\n\nAlso, I think this should be a decaying average rather than an overall average. Maybe a time factor of 1 hour or so?"
  },
  {
   "t": "2026-08-11T00:05:19Z",
   "kind": "comment",
   "who": "ajtowns",
   "assoc": "MEMBER",
   "text": "I think the idea of adding better performance monitoring could be valuable, but I don't think this is the right way of doing that:\n\n * it doesn't seem to result in actionable metrics cf https://github.com/bitcoin/bitcoin/pull/31672#issuecomment-3800200054\n * it doesn't distinguish valuable work (\"this peer provides blocks quickly and we spend cpu time validating them\") vs unproductive work (\"this peer requests the same bloom filter repeatedly\")\n * it's not comparable between peers because of differences in peer behaviour and length of time connected cf https://github.com/bitcoin/bitcoin/pull/31672#issuecomment-4546559323\n\nI still think raw-clock-time would be simpler and pretty much equally accurate as an \"introductory performance monitoring\" metric.\n\nI wonder if time per message-type (total and decaying average) might be more useful than time-per-peer?\n\nI think just generating a flame graph is likely to be more useful though, and doesn't require any code changes."
  },
  {
   "t": "2026-08-13T19:24:44Z",
   "kind": "comment",
   "who": "ajtowns",
   "assoc": "MEMBER",
   "text": "Having a per-peer \"memory-usage\" statistic (like getmempoolinfo's usage value) would probably be interesting."
  },
  {
   "t": "2026-08-21T06:40:21Z",
   "kind": "review",
   "who": "BrandonOdiwuor",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "52f1efc06afe5787fdc60a190647aadbc4981981",
   "text": "Tested this PR while catching up on Signet and collected 15 `getpeerinfo` snapshots covering height **268684 \u2192 318650** (the final ~50k blocks of IBD).\n\n(Tested on Ubuntu 24.04.4 LTS)\n\n### Results\n\n| Metric | Observation |\n|--------|-------------|\n| Peak `cpu_load` | **91.7** (one peer) |\n| Earlier high | 77.0 |\n| Near tip | Max declined to **20.4** |\n| Absolute CPU time | Individual peers accumulated up to **~158 seconds** of pure message-handler time |\n| Concentration | The single heaviest peer frequently accounted for **50\u201363%** of total observed `cpu_load` |\n| Efficiency | Best peers delivered blocks at ~0.03\u20130.05 CPU-seconds per MB; worst peers were 10\u201320\u00d7 more expensive |\n\nHigh `cpu_load` values consistently belonged to peers that delivered large volumes of block data. The metric is responsive: it rises under heavy load and falls as the node reaches the tip. There is large variance between peers, making the field useful for identifying expensive connections.\n\n### Charts\n\n**Max / Average / Median over height**\n\n**Distribution across peers at key stages**\n\n**Concentration (% of total `cpu_load` from the single heaviest peer)**\n\n`getpeerinfo` RPC data collected\n\nRaw data: [getpeerinfo.json](https://github.com/user-attachments/files/31292808/getpeerinfo.json)\n\nSome form of visibility into CPU time used by peers is useful"
  }
 ],
 "labels_log": [
  {
   "t": "2025-01-16T14:02:10Z",
   "action": "labeled",
   "label": "RPC/REST/ZMQ",
   "who": "DrahtBot"
  },
  {
   "t": "2025-01-16T14:04:59Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-01-22T15:15:28Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-06-15T11:06:42Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-06-20T09:21:10Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-01-23T13:53:56Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-29T15:29:17Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2025-01-20T12:25:48Z",
   "kind": "convert_to_draft",
   "who": "vasild"
  },
  {
   "t": "2025-01-23T09:58:20Z",
   "kind": "ready_for_review",
   "who": "vasild"
  }
 ],
 "text_chars": 27287,
 "text_tokens_estimate": 6821,
 "changed_paths": [
  "doc/release-notes-31672.md",
  "src/bitcoin-cli.cpp",
  "src/net.cpp",
  "src/net.h",
  "src/rpc/net.cpp",
  "src/util/time.cpp",
  "src/util/time.h",
  "test/functional/rpc_net.py"
 ],
 "files": [
  {
   "path": "doc/release-notes-31672.md",
   "add": 9,
   "del": 0
  },
  {
   "path": "src/bitcoin-cli.cpp",
   "add": 31,
   "del": 4
  },
  {
   "path": "src/net.cpp",
   "add": 4,
   "del": 0
  },
  {
   "path": "src/net.h",
   "add": 6,
   "del": 0
  },
  {
   "path": "src/rpc/net.cpp",
   "add": 9,
   "del": 0
  },
  {
   "path": "src/util/time.cpp",
   "add": 56,
   "del": 0
  },
  {
   "path": "src/util/time.h",
   "add": 44,
   "del": 0
  },
  {
   "path": "test/functional/rpc_net.py",
   "add": 1,
   "del": 0
  }
 ],
 "test_lines": 1,
 "git": {
  "head": "52f1efc06afe5787fdc60a190647aadbc4981981",
  "head_matches_backup": true,
  "base": "cef58341a0b2b06ca4ebfe8590cd8e93b09ce72a",
  "commits": [
   {
    "sha": "cb2eab9118",
    "subject": "rpc: add cpu_load to getpeerinfo",
    "files": 7,
    "add": 129,
    "del": 0
   },
   {
    "sha": "52f1efc06a",
    "subject": "cli: add getpeerinfo#cpu_load to -netinfo",
    "files": 1,
    "add": 31,
    "del": 4
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "14dbccee1783421c",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}