123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624 |
- defmodule Pleroma.LoadTesting.Fetcher do
- alias Pleroma.Activity
- alias Pleroma.Pagination
- alias Pleroma.Repo
- alias Pleroma.User
- alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.MastodonAPI.MastodonAPI
- alias Pleroma.Web.MastodonAPI.StatusView
- @spec run_benchmarks(User.t()) :: any()
- def run_benchmarks(user) do
- fetch_user(user)
- fetch_timelines(user)
- render_views(user)
- end
- defp formatters do
- [
- Benchee.Formatters.Console
- ]
- end
- defp fetch_user(user) do
- Benchee.run(
- %{
- "By id" => fn -> Repo.get_by(User, id: user.id) end,
- "By ap_id" => fn -> Repo.get_by(User, ap_id: user.ap_id) end,
- "By email" => fn -> Repo.get_by(User, email: user.email) end,
- "By nickname" => fn -> Repo.get_by(User, nickname: user.nickname) end
- },
- formatters: formatters()
- )
- end
- defp create_filter(user) do
- Pleroma.Filter.create(%{
- user_id: user.id,
- phrase: "must be filtered",
- hide: true,
- context: ["home"]
- })
- end
- defp delete_filter(filter), do: Repo.delete(filter)
- defp fetch_timelines(user) do
- fetch_home_timeline(user)
- fetch_home_timeline_with_filter(user)
- fetch_direct_timeline(user)
- fetch_public_timeline(user)
- fetch_public_timeline_with_filter(user)
- fetch_public_timeline(user, :with_blocks)
- fetch_public_timeline(user, :local)
- fetch_public_timeline(user, :tag)
- fetch_notifications(user)
- fetch_favourites(user)
- fetch_long_thread(user)
- fetch_timelines_with_reply_filtering(user)
- end
- defp render_views(user) do
- render_timelines(user)
- render_long_thread(user)
- end
- defp opts_for_home_timeline(user) do
- %{
- blocking_user: user,
- count: "20",
- muting_user: user,
- type: ["Create", "Announce"],
- user: user,
- with_muted: true
- }
- end
- defp fetch_home_timeline(user, title_end \\ "") do
- opts = opts_for_home_timeline(user)
- recipients = [user.ap_id | User.following(user)]
- first_page_last =
- ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse() |> List.last()
- second_page_last =
- ActivityPub.fetch_activities(recipients, Map.put(opts, :max_id, first_page_last.id))
- |> Enum.reverse()
- |> List.last()
- third_page_last =
- ActivityPub.fetch_activities(recipients, Map.put(opts, :max_id, second_page_last.id))
- |> Enum.reverse()
- |> List.last()
- forth_page_last =
- ActivityPub.fetch_activities(recipients, Map.put(opts, :max_id, third_page_last.id))
- |> Enum.reverse()
- |> List.last()
- title = "home timeline " <> title_end
- Benchee.run(
- %{
- title => fn opts -> ActivityPub.fetch_activities(recipients, opts) end
- },
- inputs: %{
- "1 page" => opts,
- "2 page" => Map.put(opts, :max_id, first_page_last.id),
- "3 page" => Map.put(opts, :max_id, second_page_last.id),
- "4 page" => Map.put(opts, :max_id, third_page_last.id),
- "5 page" => Map.put(opts, :max_id, forth_page_last.id),
- "1 page only media" => Map.put(opts, :only_media, true),
- "2 page only media" =>
- Map.put(opts, :max_id, first_page_last.id) |> Map.put(:only_media, true),
- "3 page only media" =>
- Map.put(opts, :max_id, second_page_last.id) |> Map.put(:only_media, true),
- "4 page only media" =>
- Map.put(opts, :max_id, third_page_last.id) |> Map.put(:only_media, true),
- "5 page only media" =>
- Map.put(opts, :max_id, forth_page_last.id) |> Map.put(:only_media, true)
- },
- formatters: formatters()
- )
- end
- defp fetch_home_timeline_with_filter(user) do
- {:ok, filter} = create_filter(user)
- fetch_home_timeline(user, "with filters")
- delete_filter(filter)
- end
- defp opts_for_direct_timeline(user) do
- %{
- visibility: "direct",
- blocking_user: user,
- count: "20",
- type: "Create",
- user: user,
- with_muted: true
- }
- end
- defp fetch_direct_timeline(user) do
- recipients = [user.ap_id]
- opts = opts_for_direct_timeline(user)
- first_page_last =
- recipients
- |> ActivityPub.fetch_activities_query(opts)
- |> Pagination.fetch_paginated(opts)
- |> List.last()
- opts2 = Map.put(opts, :max_id, first_page_last.id)
- second_page_last =
- recipients
- |> ActivityPub.fetch_activities_query(opts2)
- |> Pagination.fetch_paginated(opts2)
- |> List.last()
- opts3 = Map.put(opts, :max_id, second_page_last.id)
- third_page_last =
- recipients
- |> ActivityPub.fetch_activities_query(opts3)
- |> Pagination.fetch_paginated(opts3)
- |> List.last()
- opts4 = Map.put(opts, :max_id, third_page_last.id)
- forth_page_last =
- recipients
- |> ActivityPub.fetch_activities_query(opts4)
- |> Pagination.fetch_paginated(opts4)
- |> List.last()
- Benchee.run(
- %{
- "direct timeline" => fn opts ->
- ActivityPub.fetch_activities_query(recipients, opts) |> Pagination.fetch_paginated(opts)
- end
- },
- inputs: %{
- "1 page" => opts,
- "2 page" => opts2,
- "3 page" => opts3,
- "4 page" => opts4,
- "5 page" => Map.put(opts4, :max_id, forth_page_last.id)
- },
- formatters: formatters()
- )
- end
- defp opts_for_public_timeline(user) do
- %{
- type: ["Create", "Announce"],
- local_only: false,
- blocking_user: user,
- muting_user: user
- }
- end
- defp opts_for_public_timeline(user, :local) do
- %{
- type: ["Create", "Announce"],
- local_only: true,
- blocking_user: user,
- muting_user: user
- }
- end
- defp opts_for_public_timeline(user, :tag) do
- %{
- blocking_user: user,
- count: "20",
- local_only: nil,
- muting_user: user,
- tag: ["tag"],
- tag_all: [],
- tag_reject: [],
- type: "Create",
- user: user,
- with_muted: true
- }
- end
- defp fetch_public_timeline(user) do
- opts = opts_for_public_timeline(user)
- fetch_public_timeline(opts, "public timeline")
- end
- defp fetch_public_timeline_with_filter(user) do
- {:ok, filter} = create_filter(user)
- opts = opts_for_public_timeline(user)
- fetch_public_timeline(opts, "public timeline with filters")
- delete_filter(filter)
- end
- defp fetch_public_timeline(user, :local) do
- opts = opts_for_public_timeline(user, :local)
- fetch_public_timeline(opts, "public timeline only local")
- end
- defp fetch_public_timeline(user, :tag) do
- opts = opts_for_public_timeline(user, :tag)
- fetch_public_timeline(opts, "hashtag timeline")
- end
- defp fetch_public_timeline(user, :only_media) do
- opts = opts_for_public_timeline(user) |> Map.put(:only_media, true)
- fetch_public_timeline(opts, "public timeline only media")
- end
- defp fetch_public_timeline(user, :with_blocks) do
- opts = opts_for_public_timeline(user)
- remote_non_friends = Agent.get(:non_friends_remote, & &1)
- Benchee.run(%{
- "public timeline without blocks" => fn ->
- ActivityPub.fetch_public_activities(opts)
- end
- })
- Enum.each(remote_non_friends, fn non_friend ->
- {:ok, _} = User.block(user, non_friend)
- end)
- user = User.get_by_id(user.id)
- opts = Map.put(opts, :blocking_user, user)
- Benchee.run(%{
- "public timeline with user block" => fn ->
- ActivityPub.fetch_public_activities(opts)
- end
- })
- domains =
- Enum.reduce(remote_non_friends, [], fn non_friend, domains ->
- {:ok, _user} = User.unblock(user, non_friend)
- %{host: host} = URI.parse(non_friend.ap_id)
- [host | domains]
- end)
- domains = Enum.uniq(domains)
- Enum.each(domains, fn domain ->
- {:ok, _} = User.block_domain(user, domain)
- end)
- user = User.get_by_id(user.id)
- opts = Map.put(opts, :blocking_user, user)
- Benchee.run(%{
- "public timeline with domain block" => fn ->
- ActivityPub.fetch_public_activities(opts)
- end
- })
- end
- defp fetch_public_timeline(opts, title) when is_binary(title) do
- first_page_last = ActivityPub.fetch_public_activities(opts) |> List.last()
- second_page_last =
- ActivityPub.fetch_public_activities(Map.put(opts, :max_id, first_page_last.id))
- |> List.last()
- third_page_last =
- ActivityPub.fetch_public_activities(Map.put(opts, :max_id, second_page_last.id))
- |> List.last()
- forth_page_last =
- ActivityPub.fetch_public_activities(Map.put(opts, :max_id, third_page_last.id))
- |> List.last()
- Benchee.run(
- %{
- title => fn opts ->
- ActivityPub.fetch_public_activities(opts)
- end
- },
- inputs: %{
- "1 page" => opts,
- "2 page" => Map.put(opts, :max_id, first_page_last.id),
- "3 page" => Map.put(opts, :max_id, second_page_last.id),
- "4 page" => Map.put(opts, :max_id, third_page_last.id),
- "5 page" => Map.put(opts, :max_id, forth_page_last.id)
- },
- formatters: formatters()
- )
- end
- defp opts_for_notifications do
- %{count: "20", with_muted: true}
- end
- defp fetch_notifications(user) do
- opts = opts_for_notifications()
- first_page_last = MastodonAPI.get_notifications(user, opts) |> List.last()
- second_page_last =
- MastodonAPI.get_notifications(user, Map.put(opts, :max_id, first_page_last.id))
- |> List.last()
- third_page_last =
- MastodonAPI.get_notifications(user, Map.put(opts, :max_id, second_page_last.id))
- |> List.last()
- forth_page_last =
- MastodonAPI.get_notifications(user, Map.put(opts, :max_id, third_page_last.id))
- |> List.last()
- Benchee.run(
- %{
- "Notifications" => fn opts ->
- MastodonAPI.get_notifications(user, opts)
- end
- },
- inputs: %{
- "1 page" => opts,
- "2 page" => Map.put(opts, :max_id, first_page_last.id),
- "3 page" => Map.put(opts, :max_id, second_page_last.id),
- "4 page" => Map.put(opts, :max_id, third_page_last.id),
- "5 page" => Map.put(opts, :max_id, forth_page_last.id)
- },
- formatters: formatters()
- )
- end
- defp fetch_favourites(user) do
- first_page_last = ActivityPub.fetch_favourites(user) |> List.last()
- second_page_last =
- ActivityPub.fetch_favourites(user, %{:max_id => first_page_last.id}) |> List.last()
- third_page_last =
- ActivityPub.fetch_favourites(user, %{:max_id => second_page_last.id}) |> List.last()
- forth_page_last =
- ActivityPub.fetch_favourites(user, %{:max_id => third_page_last.id}) |> List.last()
- Benchee.run(
- %{
- "Favourites" => fn opts ->
- ActivityPub.fetch_favourites(user, opts)
- end
- },
- inputs: %{
- "1 page" => %{},
- "2 page" => %{:max_id => first_page_last.id},
- "3 page" => %{:max_id => second_page_last.id},
- "4 page" => %{:max_id => third_page_last.id},
- "5 page" => %{:max_id => forth_page_last.id}
- },
- formatters: formatters()
- )
- end
- defp opts_for_long_thread(user) do
- %{
- blocking_user: user,
- user: user
- }
- end
- defp fetch_long_thread(user) do
- %{public_thread: public, private_thread: private} =
- Agent.get(:benchmark_state, fn state -> state end)
- opts = opts_for_long_thread(user)
- private_input = {private.data["context"], Map.put(opts, :exclude_id, private.id)}
- public_input = {public.data["context"], Map.put(opts, :exclude_id, public.id)}
- Benchee.run(
- %{
- "fetch context" => fn {context, opts} ->
- ActivityPub.fetch_activities_for_context(context, opts)
- end
- },
- inputs: %{
- "Private long thread" => private_input,
- "Public long thread" => public_input
- },
- formatters: formatters()
- )
- end
- defp render_timelines(user) do
- opts = opts_for_home_timeline(user)
- recipients = [user.ap_id | User.following(user)]
- home_activities = ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse()
- recipients = [user.ap_id]
- opts = opts_for_direct_timeline(user)
- direct_activities =
- recipients
- |> ActivityPub.fetch_activities_query(opts)
- |> Pagination.fetch_paginated(opts)
- opts = opts_for_public_timeline(user)
- public_activities = ActivityPub.fetch_public_activities(opts)
- opts = opts_for_public_timeline(user, :tag)
- tag_activities = ActivityPub.fetch_public_activities(opts)
- opts = opts_for_notifications()
- notifications = MastodonAPI.get_notifications(user, opts)
- favourites = ActivityPub.fetch_favourites(user)
- Benchee.run(
- %{
- "Rendering home timeline" => fn ->
- StatusView.render("index.json", %{
- activities: home_activities,
- for: user,
- as: :activity
- })
- end,
- "Rendering direct timeline" => fn ->
- StatusView.render("index.json", %{
- activities: direct_activities,
- for: user,
- as: :activity
- })
- end,
- "Rendering public timeline" => fn ->
- StatusView.render("index.json", %{
- activities: public_activities,
- for: user,
- as: :activity
- })
- end,
- "Rendering tag timeline" => fn ->
- StatusView.render("index.json", %{
- activities: tag_activities,
- for: user,
- as: :activity
- })
- end,
- "Rendering notifications" => fn ->
- Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
- notifications: notifications,
- for: user
- })
- end,
- "Rendering favourites timeline" => fn ->
- StatusView.render("index.json", %{
- activities: favourites,
- for: user,
- as: :activity
- })
- end
- },
- formatters: formatters()
- )
- end
- defp render_long_thread(user) do
- %{public_thread: public, private_thread: private} =
- Agent.get(:benchmark_state, fn state -> state end)
- opts = %{for: user}
- public_activity = Activity.get_by_id_with_object(public.id)
- private_activity = Activity.get_by_id_with_object(private.id)
- Benchee.run(
- %{
- "render" => fn opts ->
- StatusView.render("show.json", opts)
- end
- },
- inputs: %{
- "Public root" => Map.put(opts, :activity, public_activity),
- "Private root" => Map.put(opts, :activity, private_activity)
- },
- formatters: formatters()
- )
- fetch_opts = opts_for_long_thread(user)
- public_context =
- ActivityPub.fetch_activities_for_context(
- public.data["context"],
- Map.put(fetch_opts, :exclude_id, public.id)
- )
- private_context =
- ActivityPub.fetch_activities_for_context(
- private.data["context"],
- Map.put(fetch_opts, :exclude_id, private.id)
- )
- Benchee.run(
- %{
- "render" => fn opts ->
- StatusView.render("context.json", opts)
- end
- },
- inputs: %{
- "Public context" => %{user: user, activity: public_activity, activities: public_context},
- "Private context" => %{
- user: user,
- activity: private_activity,
- activities: private_context
- }
- },
- formatters: formatters()
- )
- end
- defp fetch_timelines_with_reply_filtering(user) do
- public_params = opts_for_public_timeline(user)
- Benchee.run(
- %{
- "Public timeline without reply filtering" => fn ->
- ActivityPub.fetch_public_activities(public_params)
- end,
- "Public timeline with reply filtering - following" => fn ->
- public_params
- |> Map.put(:reply_visibility, "following")
- |> Map.put(:reply_filtering_user, user)
- |> ActivityPub.fetch_public_activities()
- end,
- "Public timeline with reply filtering - self" => fn ->
- public_params
- |> Map.put(:reply_visibility, "self")
- |> Map.put(:reply_filtering_user, user)
- |> ActivityPub.fetch_public_activities()
- end
- },
- formatters: formatters()
- )
- private_params = opts_for_home_timeline(user)
- recipients = [user.ap_id | User.following(user)]
- Benchee.run(
- %{
- "Home timeline without reply filtering" => fn ->
- ActivityPub.fetch_activities(recipients, private_params)
- end,
- "Home timeline with reply filtering - following" => fn ->
- private_params =
- private_params
- |> Map.put(:reply_filtering_user, user)
- |> Map.put(:reply_visibility, "following")
- ActivityPub.fetch_activities(recipients, private_params)
- end,
- "Home timeline with reply filtering - self" => fn ->
- private_params =
- private_params
- |> Map.put(:reply_filtering_user, user)
- |> Map.put(:reply_visibility, "self")
- ActivityPub.fetch_activities(recipients, private_params)
- end
- },
- formatters: formatters()
- )
- end
- end
|