Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

624 行
17KB

  1. defmodule Pleroma.LoadTesting.Fetcher do
  2. alias Pleroma.Activity
  3. alias Pleroma.Pagination
  4. alias Pleroma.Repo
  5. alias Pleroma.User
  6. alias Pleroma.Web.ActivityPub.ActivityPub
  7. alias Pleroma.Web.MastodonAPI.MastodonAPI
  8. alias Pleroma.Web.MastodonAPI.StatusView
  9. @spec run_benchmarks(User.t()) :: any()
  10. def run_benchmarks(user) do
  11. fetch_user(user)
  12. fetch_timelines(user)
  13. render_views(user)
  14. end
  15. defp formatters do
  16. [
  17. Benchee.Formatters.Console
  18. ]
  19. end
  20. defp fetch_user(user) do
  21. Benchee.run(
  22. %{
  23. "By id" => fn -> Repo.get_by(User, id: user.id) end,
  24. "By ap_id" => fn -> Repo.get_by(User, ap_id: user.ap_id) end,
  25. "By email" => fn -> Repo.get_by(User, email: user.email) end,
  26. "By nickname" => fn -> Repo.get_by(User, nickname: user.nickname) end
  27. },
  28. formatters: formatters()
  29. )
  30. end
  31. defp create_filter(user) do
  32. Pleroma.Filter.create(%Pleroma.Filter{
  33. user_id: user.id,
  34. phrase: "must be filtered",
  35. hide: true
  36. })
  37. end
  38. defp delete_filter(filter), do: Repo.delete(filter)
  39. defp fetch_timelines(user) do
  40. fetch_home_timeline(user)
  41. fetch_home_timeline_with_filter(user)
  42. fetch_direct_timeline(user)
  43. fetch_public_timeline(user)
  44. fetch_public_timeline_with_filter(user)
  45. fetch_public_timeline(user, :with_blocks)
  46. fetch_public_timeline(user, :local)
  47. fetch_public_timeline(user, :tag)
  48. fetch_notifications(user)
  49. fetch_favourites(user)
  50. fetch_long_thread(user)
  51. fetch_timelines_with_reply_filtering(user)
  52. end
  53. defp render_views(user) do
  54. render_timelines(user)
  55. render_long_thread(user)
  56. end
  57. defp opts_for_home_timeline(user) do
  58. %{
  59. blocking_user: user,
  60. count: "20",
  61. muting_user: user,
  62. type: ["Create", "Announce"],
  63. user: user,
  64. with_muted: true
  65. }
  66. end
  67. defp fetch_home_timeline(user, title_end \\ "") do
  68. opts = opts_for_home_timeline(user)
  69. recipients = [user.ap_id | User.following(user)]
  70. first_page_last =
  71. ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse() |> List.last()
  72. second_page_last =
  73. ActivityPub.fetch_activities(recipients, Map.put(opts, :max_id, first_page_last.id))
  74. |> Enum.reverse()
  75. |> List.last()
  76. third_page_last =
  77. ActivityPub.fetch_activities(recipients, Map.put(opts, :max_id, second_page_last.id))
  78. |> Enum.reverse()
  79. |> List.last()
  80. forth_page_last =
  81. ActivityPub.fetch_activities(recipients, Map.put(opts, :max_id, third_page_last.id))
  82. |> Enum.reverse()
  83. |> List.last()
  84. title = "home timeline " <> title_end
  85. Benchee.run(
  86. %{
  87. title => fn opts -> ActivityPub.fetch_activities(recipients, opts) end
  88. },
  89. inputs: %{
  90. "1 page" => opts,
  91. "2 page" => Map.put(opts, :max_id, first_page_last.id),
  92. "3 page" => Map.put(opts, :max_id, second_page_last.id),
  93. "4 page" => Map.put(opts, :max_id, third_page_last.id),
  94. "5 page" => Map.put(opts, :max_id, forth_page_last.id),
  95. "1 page only media" => Map.put(opts, :only_media, true),
  96. "2 page only media" =>
  97. Map.put(opts, :max_id, first_page_last.id) |> Map.put(:only_media, true),
  98. "3 page only media" =>
  99. Map.put(opts, :max_id, second_page_last.id) |> Map.put(:only_media, true),
  100. "4 page only media" =>
  101. Map.put(opts, :max_id, third_page_last.id) |> Map.put(:only_media, true),
  102. "5 page only media" =>
  103. Map.put(opts, :max_id, forth_page_last.id) |> Map.put(:only_media, true)
  104. },
  105. formatters: formatters()
  106. )
  107. end
  108. defp fetch_home_timeline_with_filter(user) do
  109. {:ok, filter} = create_filter(user)
  110. fetch_home_timeline(user, "with filters")
  111. delete_filter(filter)
  112. end
  113. defp opts_for_direct_timeline(user) do
  114. %{
  115. visibility: "direct",
  116. blocking_user: user,
  117. count: "20",
  118. type: "Create",
  119. user: user,
  120. with_muted: true
  121. }
  122. end
  123. defp fetch_direct_timeline(user) do
  124. recipients = [user.ap_id]
  125. opts = opts_for_direct_timeline(user)
  126. first_page_last =
  127. recipients
  128. |> ActivityPub.fetch_activities_query(opts)
  129. |> Pagination.fetch_paginated(opts)
  130. |> List.last()
  131. opts2 = Map.put(opts, :max_id, first_page_last.id)
  132. second_page_last =
  133. recipients
  134. |> ActivityPub.fetch_activities_query(opts2)
  135. |> Pagination.fetch_paginated(opts2)
  136. |> List.last()
  137. opts3 = Map.put(opts, :max_id, second_page_last.id)
  138. third_page_last =
  139. recipients
  140. |> ActivityPub.fetch_activities_query(opts3)
  141. |> Pagination.fetch_paginated(opts3)
  142. |> List.last()
  143. opts4 = Map.put(opts, :max_id, third_page_last.id)
  144. forth_page_last =
  145. recipients
  146. |> ActivityPub.fetch_activities_query(opts4)
  147. |> Pagination.fetch_paginated(opts4)
  148. |> List.last()
  149. Benchee.run(
  150. %{
  151. "direct timeline" => fn opts ->
  152. ActivityPub.fetch_activities_query(recipients, opts) |> Pagination.fetch_paginated(opts)
  153. end
  154. },
  155. inputs: %{
  156. "1 page" => opts,
  157. "2 page" => opts2,
  158. "3 page" => opts3,
  159. "4 page" => opts4,
  160. "5 page" => Map.put(opts4, :max_id, forth_page_last.id)
  161. },
  162. formatters: formatters()
  163. )
  164. end
  165. defp opts_for_public_timeline(user) do
  166. %{
  167. type: ["Create", "Announce"],
  168. local_only: false,
  169. blocking_user: user,
  170. muting_user: user
  171. }
  172. end
  173. defp opts_for_public_timeline(user, :local) do
  174. %{
  175. type: ["Create", "Announce"],
  176. local_only: true,
  177. blocking_user: user,
  178. muting_user: user
  179. }
  180. end
  181. defp opts_for_public_timeline(user, :tag) do
  182. %{
  183. blocking_user: user,
  184. count: "20",
  185. local_only: nil,
  186. muting_user: user,
  187. tag: ["tag"],
  188. tag_all: [],
  189. tag_reject: [],
  190. type: "Create",
  191. user: user,
  192. with_muted: true
  193. }
  194. end
  195. defp fetch_public_timeline(user) do
  196. opts = opts_for_public_timeline(user)
  197. fetch_public_timeline(opts, "public timeline")
  198. end
  199. defp fetch_public_timeline_with_filter(user) do
  200. {:ok, filter} = create_filter(user)
  201. opts = opts_for_public_timeline(user)
  202. fetch_public_timeline(opts, "public timeline with filters")
  203. delete_filter(filter)
  204. end
  205. defp fetch_public_timeline(user, :local) do
  206. opts = opts_for_public_timeline(user, :local)
  207. fetch_public_timeline(opts, "public timeline only local")
  208. end
  209. defp fetch_public_timeline(user, :tag) do
  210. opts = opts_for_public_timeline(user, :tag)
  211. fetch_public_timeline(opts, "hashtag timeline")
  212. end
  213. defp fetch_public_timeline(user, :only_media) do
  214. opts = opts_for_public_timeline(user) |> Map.put(:only_media, true)
  215. fetch_public_timeline(opts, "public timeline only media")
  216. end
  217. defp fetch_public_timeline(user, :with_blocks) do
  218. opts = opts_for_public_timeline(user)
  219. remote_non_friends = Agent.get(:non_friends_remote, & &1)
  220. Benchee.run(%{
  221. "public timeline without blocks" => fn ->
  222. ActivityPub.fetch_public_activities(opts)
  223. end
  224. })
  225. Enum.each(remote_non_friends, fn non_friend ->
  226. {:ok, _} = User.block(user, non_friend)
  227. end)
  228. user = User.get_by_id(user.id)
  229. opts = Map.put(opts, :blocking_user, user)
  230. Benchee.run(%{
  231. "public timeline with user block" => fn ->
  232. ActivityPub.fetch_public_activities(opts)
  233. end
  234. })
  235. domains =
  236. Enum.reduce(remote_non_friends, [], fn non_friend, domains ->
  237. {:ok, _user} = User.unblock(user, non_friend)
  238. %{host: host} = URI.parse(non_friend.ap_id)
  239. [host | domains]
  240. end)
  241. domains = Enum.uniq(domains)
  242. Enum.each(domains, fn domain ->
  243. {:ok, _} = User.block_domain(user, domain)
  244. end)
  245. user = User.get_by_id(user.id)
  246. opts = Map.put(opts, :blocking_user, user)
  247. Benchee.run(%{
  248. "public timeline with domain block" => fn ->
  249. ActivityPub.fetch_public_activities(opts)
  250. end
  251. })
  252. end
  253. defp fetch_public_timeline(opts, title) when is_binary(title) do
  254. first_page_last = ActivityPub.fetch_public_activities(opts) |> List.last()
  255. second_page_last =
  256. ActivityPub.fetch_public_activities(Map.put(opts, :max_id, first_page_last.id))
  257. |> List.last()
  258. third_page_last =
  259. ActivityPub.fetch_public_activities(Map.put(opts, :max_id, second_page_last.id))
  260. |> List.last()
  261. forth_page_last =
  262. ActivityPub.fetch_public_activities(Map.put(opts, :max_id, third_page_last.id))
  263. |> List.last()
  264. Benchee.run(
  265. %{
  266. title => fn opts ->
  267. ActivityPub.fetch_public_activities(opts)
  268. end
  269. },
  270. inputs: %{
  271. "1 page" => opts,
  272. "2 page" => Map.put(opts, :max_id, first_page_last.id),
  273. "3 page" => Map.put(opts, :max_id, second_page_last.id),
  274. "4 page" => Map.put(opts, :max_id, third_page_last.id),
  275. "5 page" => Map.put(opts, :max_id, forth_page_last.id)
  276. },
  277. formatters: formatters()
  278. )
  279. end
  280. defp opts_for_notifications do
  281. %{count: "20", with_muted: true}
  282. end
  283. defp fetch_notifications(user) do
  284. opts = opts_for_notifications()
  285. first_page_last = MastodonAPI.get_notifications(user, opts) |> List.last()
  286. second_page_last =
  287. MastodonAPI.get_notifications(user, Map.put(opts, :max_id, first_page_last.id))
  288. |> List.last()
  289. third_page_last =
  290. MastodonAPI.get_notifications(user, Map.put(opts, :max_id, second_page_last.id))
  291. |> List.last()
  292. forth_page_last =
  293. MastodonAPI.get_notifications(user, Map.put(opts, :max_id, third_page_last.id))
  294. |> List.last()
  295. Benchee.run(
  296. %{
  297. "Notifications" => fn opts ->
  298. MastodonAPI.get_notifications(user, opts)
  299. end
  300. },
  301. inputs: %{
  302. "1 page" => opts,
  303. "2 page" => Map.put(opts, :max_id, first_page_last.id),
  304. "3 page" => Map.put(opts, :max_id, second_page_last.id),
  305. "4 page" => Map.put(opts, :max_id, third_page_last.id),
  306. "5 page" => Map.put(opts, :max_id, forth_page_last.id)
  307. },
  308. formatters: formatters()
  309. )
  310. end
  311. defp fetch_favourites(user) do
  312. first_page_last = ActivityPub.fetch_favourites(user) |> List.last()
  313. second_page_last =
  314. ActivityPub.fetch_favourites(user, %{:max_id => first_page_last.id}) |> List.last()
  315. third_page_last =
  316. ActivityPub.fetch_favourites(user, %{:max_id => second_page_last.id}) |> List.last()
  317. forth_page_last =
  318. ActivityPub.fetch_favourites(user, %{:max_id => third_page_last.id}) |> List.last()
  319. Benchee.run(
  320. %{
  321. "Favourites" => fn opts ->
  322. ActivityPub.fetch_favourites(user, opts)
  323. end
  324. },
  325. inputs: %{
  326. "1 page" => %{},
  327. "2 page" => %{:max_id => first_page_last.id},
  328. "3 page" => %{:max_id => second_page_last.id},
  329. "4 page" => %{:max_id => third_page_last.id},
  330. "5 page" => %{:max_id => forth_page_last.id}
  331. },
  332. formatters: formatters()
  333. )
  334. end
  335. defp opts_for_long_thread(user) do
  336. %{
  337. blocking_user: user,
  338. user: user
  339. }
  340. end
  341. defp fetch_long_thread(user) do
  342. %{public_thread: public, private_thread: private} =
  343. Agent.get(:benchmark_state, fn state -> state end)
  344. opts = opts_for_long_thread(user)
  345. private_input = {private.data["context"], Map.put(opts, :exclude_id, private.id)}
  346. public_input = {public.data["context"], Map.put(opts, :exclude_id, public.id)}
  347. Benchee.run(
  348. %{
  349. "fetch context" => fn {context, opts} ->
  350. ActivityPub.fetch_activities_for_context(context, opts)
  351. end
  352. },
  353. inputs: %{
  354. "Private long thread" => private_input,
  355. "Public long thread" => public_input
  356. },
  357. formatters: formatters()
  358. )
  359. end
  360. defp render_timelines(user) do
  361. opts = opts_for_home_timeline(user)
  362. recipients = [user.ap_id | User.following(user)]
  363. home_activities = ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse()
  364. recipients = [user.ap_id]
  365. opts = opts_for_direct_timeline(user)
  366. direct_activities =
  367. recipients
  368. |> ActivityPub.fetch_activities_query(opts)
  369. |> Pagination.fetch_paginated(opts)
  370. opts = opts_for_public_timeline(user)
  371. public_activities = ActivityPub.fetch_public_activities(opts)
  372. opts = opts_for_public_timeline(user, :tag)
  373. tag_activities = ActivityPub.fetch_public_activities(opts)
  374. opts = opts_for_notifications()
  375. notifications = MastodonAPI.get_notifications(user, opts)
  376. favourites = ActivityPub.fetch_favourites(user)
  377. Benchee.run(
  378. %{
  379. "Rendering home timeline" => fn ->
  380. StatusView.render("index.json", %{
  381. activities: home_activities,
  382. for: user,
  383. as: :activity
  384. })
  385. end,
  386. "Rendering direct timeline" => fn ->
  387. StatusView.render("index.json", %{
  388. activities: direct_activities,
  389. for: user,
  390. as: :activity
  391. })
  392. end,
  393. "Rendering public timeline" => fn ->
  394. StatusView.render("index.json", %{
  395. activities: public_activities,
  396. for: user,
  397. as: :activity
  398. })
  399. end,
  400. "Rendering tag timeline" => fn ->
  401. StatusView.render("index.json", %{
  402. activities: tag_activities,
  403. for: user,
  404. as: :activity
  405. })
  406. end,
  407. "Rendering notifications" => fn ->
  408. Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
  409. notifications: notifications,
  410. for: user
  411. })
  412. end,
  413. "Rendering favourites timeline" => fn ->
  414. StatusView.render("index.json", %{
  415. activities: favourites,
  416. for: user,
  417. as: :activity
  418. })
  419. end
  420. },
  421. formatters: formatters()
  422. )
  423. end
  424. defp render_long_thread(user) do
  425. %{public_thread: public, private_thread: private} =
  426. Agent.get(:benchmark_state, fn state -> state end)
  427. opts = %{for: user}
  428. public_activity = Activity.get_by_id_with_object(public.id)
  429. private_activity = Activity.get_by_id_with_object(private.id)
  430. Benchee.run(
  431. %{
  432. "render" => fn opts ->
  433. StatusView.render("show.json", opts)
  434. end
  435. },
  436. inputs: %{
  437. "Public root" => Map.put(opts, :activity, public_activity),
  438. "Private root" => Map.put(opts, :activity, private_activity)
  439. },
  440. formatters: formatters()
  441. )
  442. fetch_opts = opts_for_long_thread(user)
  443. public_context =
  444. ActivityPub.fetch_activities_for_context(
  445. public.data["context"],
  446. Map.put(fetch_opts, :exclude_id, public.id)
  447. )
  448. private_context =
  449. ActivityPub.fetch_activities_for_context(
  450. private.data["context"],
  451. Map.put(fetch_opts, :exclude_id, private.id)
  452. )
  453. Benchee.run(
  454. %{
  455. "render" => fn opts ->
  456. StatusView.render("context.json", opts)
  457. end
  458. },
  459. inputs: %{
  460. "Public context" => %{user: user, activity: public_activity, activities: public_context},
  461. "Private context" => %{
  462. user: user,
  463. activity: private_activity,
  464. activities: private_context
  465. }
  466. },
  467. formatters: formatters()
  468. )
  469. end
  470. defp fetch_timelines_with_reply_filtering(user) do
  471. public_params = opts_for_public_timeline(user)
  472. Benchee.run(
  473. %{
  474. "Public timeline without reply filtering" => fn ->
  475. ActivityPub.fetch_public_activities(public_params)
  476. end,
  477. "Public timeline with reply filtering - following" => fn ->
  478. public_params
  479. |> Map.put(:reply_visibility, "following")
  480. |> Map.put(:reply_filtering_user, user)
  481. |> ActivityPub.fetch_public_activities()
  482. end,
  483. "Public timeline with reply filtering - self" => fn ->
  484. public_params
  485. |> Map.put(:reply_visibility, "self")
  486. |> Map.put(:reply_filtering_user, user)
  487. |> ActivityPub.fetch_public_activities()
  488. end
  489. },
  490. formatters: formatters()
  491. )
  492. private_params = opts_for_home_timeline(user)
  493. recipients = [user.ap_id | User.following(user)]
  494. Benchee.run(
  495. %{
  496. "Home timeline without reply filtering" => fn ->
  497. ActivityPub.fetch_activities(recipients, private_params)
  498. end,
  499. "Home timeline with reply filtering - following" => fn ->
  500. private_params =
  501. private_params
  502. |> Map.put(:reply_filtering_user, user)
  503. |> Map.put(:reply_visibility, "following")
  504. ActivityPub.fetch_activities(recipients, private_params)
  505. end,
  506. "Home timeline with reply filtering - self" => fn ->
  507. private_params =
  508. private_params
  509. |> Map.put(:reply_filtering_user, user)
  510. |> Map.put(:reply_visibility, "self")
  511. ActivityPub.fetch_activities(recipients, private_params)
  512. end
  513. },
  514. formatters: formatters()
  515. )
  516. end
  517. end