Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
Dominik Charousset
@Neverlord
Looks like it.
Dominik Lohmann
@dominiklohmann
Is there an easy way to detect for a given response promise whether the request associated with it timed out already?
Dominik Charousset
@Neverlord
No, the actor only knows once it sees the timeout message.
Dominik Charousset
@Neverlord

I've just assembled a new web_socket::accept function that nicely integrates with flows: https://github.com/actor-framework/actor-framework/blob/070b3ae157ed7866cf3c9785ca8fceead415ae92/examples/web_socket/echo.cpp.

I wouldn't recommend checking out the caf-net branch quite yet, though. 🙂

nohous
@nohous
is this a right place to talk about possible CAF applications?
Dominik Charousset
@Neverlord
@nohous sure, welcome to the chat! :)
Agor Maxime
@4rzael
Hi everyone !
I'm working on a fairly large embedded project running on an MCU (esp32), where it seems like an actor model would make a lot of sense. Has anyone here used CAF on similar environments ?
I was wondering how applicable it is to embedded programming ? More specifically, on the memory usage aspect:
  • I'm trying to avoid dynamic allocations after initialization. Are there operations that would not be usable in this context ? Actor instantiation ? Message passing ? Promise / Delaying ?
  • Is there any way to provide custom allocators to the framework ?
  • What is the memory footprint of an event-based actor ? The docs seems to state "A few hundred of bytes". Is that correct ?
    I know this question is quite broad, and I'm sorry for that. I'm just trying to understand feasibility before going a lot deeper in how the framework works
Dominik Charousset
@Neverlord
I don't have experience for running in such an environment, but regarding the other questions: Spawning an actor as well as message passing rely on memory allocations. There's no support for passing custom allocators to the framework. That allocator would have to support a wide range of different use scenarios (messages vs actors vs per-actor state), so it would probably not give much value to add support a allocator. And passing different allocators to different system components would get tricky. Few hundred bytes: that should still hold (unless you subtype one of the actors and make it huge). Haven't measured it in a while, though. An actor also may allocate during initialization depending on what you do, e.g., setting custom handlers. The behavior is also heap-allocated, so there's a couple of allocations per spawn.
2 replies
CAF uses ref counting, so at least it generally releases memory as soon as possible.
Farafonov Alexey
@farafonov-alexey

Hello, @Neverlord! We have library(dll) that exports some functions. Inside this functions we have this pseudo code

caf::scoped_actor self{system_->system()};
self
      ->request(actor1, atom1, ...)
      .receive(
        [&](....) {
          ....
        },
        [&](caf::error& err) {
          ....
        });

Cause this library methods should return result we use blocking behavior.

If we use this library from Qt application actor1 recieves atom1 almost instantly (1-2ms) after calling request. Otherwise if we call this same method from console app actor1 recieves atom1 after a delay of 10-15ms. Cause we call this function multiple times this delay seems critical. We don't understand the reason of this behavior nor how to overcome this :(.

CAF version 0.17.4
Dominik Charousset
@Neverlord
10-15ms seems like a lot. I don't really see what "Qt app" vs "console app" entails, though. Did you maybe reproduce this with some small-ish code that I could look at?
Farafonov Alexey
@farafonov-alexey
@Neverlord Well not really smallish =), but as minimal as i can do right now. https://github.com/farafonov-alexey/caf-request-recieve
From request till actor recieve right now i get approx 15-20ms. Could you please look maybe I'm missing something.
image.png
Dominik Charousset
@Neverlord
How are your scheduler settings? Relaxed sleep is 10ms by default: https://actor-framework.readthedocs.io/en/stable/ConfiguringActorApplications.html#configuration-files
Farafonov Alexey
@farafonov-alexey
Well i think its default, how can I set this value programmatically?)
Dominik Charousset
@Neverlord
If you're using the default scaffold with CAF_MAIN, you can pass --dump-config or in source code get_or(<key>, <default>). But if you're not setting anything then it's 10ms. It seems like your example does ultimately the same loop, though. So it's weird that it behaves differently when calling it from a Qt thread.
Farafonov Alexey
@farafonov-alexey
And from begin till end it gives 15 ms
image.png

10-15ms seems like a lot. I don't really see what "Qt app" vs "console app" entails, though. Did you maybe reproduce this with some small-ish code that I could look at?

@Neverlord this is ok or "a lot"?

Dominik Charousset
@Neverlord
@farafonov-alexey 15ms is definitely more latency than I'd expect. Since you can reproduce this even with the hello world example, let me double-check this on my end to see if the 15ms may be related to OS/HW combinations.
Farafonov Alexey
@farafonov-alexey
I change relaxed-sleep-duration but without effect
Dominik Charousset
@Neverlord
Ok. Let me play around with this a bit and get back to you. :)
Dominik Charousset
@Neverlord
@farafonov-alexey I can't speak to your HW setup, but at least on my machine, message passing performance looks how it ought to. Here's the test code:
#include <string>
#include <iostream>

#include "caf/actor_ostream.hpp"
#include "caf/actor_system.hpp"
#include "caf/caf_main.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/timestamp.hpp"

using namespace caf;

behavior testee() {
  return {
    [](timestamp t0) {
      auto t1 = make_timestamp();
      auto delta = t1 - t0;
      std::cout << "t0: " << caf::deep_to_string(t0) << '\n'
                << "t1: " << caf::deep_to_string(t1) << '\n'
                << "delta: " << caf::deep_to_string(delta) << '\n';
    },
  };
}

void caf_main(actor_system& sys) {
  scoped_actor self{sys};
  auto aut = self->spawn(testee);
  self->send(aut, make_timestamp());
}

CAF_MAIN()
And a couple of runs:
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
t0: "2022-05-09T19:13:01.901"
t1: "2022-05-09T19:13:01.901"
delta: 52us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
t0: "2022-05-09T19:14:22.067"
t1: "2022-05-09T19:14:22.067"
delta: 26us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
t0: "2022-05-09T19:14:22.945"
t1: "2022-05-09T19:14:22.945"
delta: 19us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
t0: "2022-05-09T19:14:23.442"
t1: "2022-05-09T19:14:23.442"
delta: 89us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
t0: "2022-05-09T19:14:23.921"
t1: "2022-05-09T19:14:23.922"
delta: 94us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
t0: "2022-05-09T19:14:24.403"
t1: "2022-05-09T19:14:24.403"
delta: 26us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
t0: "2022-05-09T19:14:24.827"
t1: "2022-05-09T19:14:24.827"
delta: 68us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
t0: "2022-05-09T19:14:25.242"
t1: "2022-05-09T19:14:25.242"
delta: 23us
Release build with current master.
Dominik Charousset
@Neverlord
And here's a version with request-response:
#include <string>
#include <iostream>

#include "caf/actor_ostream.hpp"
#include "caf/actor_system.hpp"
#include "caf/caf_main.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/timestamp.hpp"

using namespace caf;

using namespace std::literals;

behavior clock_actor() {
  return {
    [](get_atom) {
      return make_timestamp();
    }
  };
}

behavior testee() {
  return {
    [](timestamp t0) {
      auto t1 = make_timestamp();
      auto delta = t1 - t0;
      std::cout << "async:\n"
                << "t0: " << caf::deep_to_string(t0) << '\n'
                << "t1: " << caf::deep_to_string(t1) << '\n'
                << "delta: " << caf::deep_to_string(delta) << '\n';
    },
  };
}

void caf_main(actor_system& sys) {
  scoped_actor self{sys};
  // request-response
  auto clk = self->spawn(clock_actor);
  auto t0 = make_timestamp();
  self->request(clk, 5s, get_atom_v)
    .receive(
      [&](timestamp t1) {
        auto t2 = make_timestamp();
        std::cout << "request-response:\n"
                  << "t0: " << caf::deep_to_string(t0) << '\n'
                  << "t1: " << caf::deep_to_string(t1) << '\n'
                  << "t2: " << caf::deep_to_string(t2) << '\n'
                  << "delta (full): " << caf::deep_to_string(t2 - t0) << '\n'
                  << "delta (self -> clock): " << caf::deep_to_string(t1 - t0) << '\n'
                  << "delta (clock -> self): " << caf::deep_to_string(t2 - t1) << '\n';
      },
      [](const error&) {});
  // async
  auto aut = self->spawn(testee);
  self->send(aut, make_timestamp());
}

CAF_MAIN()
The times also are in microsecond range:
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
request-response:
t0: "2022-05-09T19:24:10.369"
t1: "2022-05-09T19:24:10.369"
t2: "2022-05-09T19:24:10.369"
delta (full): 52us
delta (self -> clock): 43us
delta (clock -> self): 9us
async:
t0: "2022-05-09T19:24:10.370"
t1: "2022-05-09T19:24:10.370"
delta: 73us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
request-response:
t0: "2022-05-09T19:24:11.077"
t1: "2022-05-09T19:24:11.077"
t2: "2022-05-09T19:24:11.077"
delta (full): 51us
delta (self -> clock): 35us
delta (clock -> self): 16us
async:
t0: "2022-05-09T19:24:11.077"
t1: "2022-05-09T19:24:11.078"
delta: 70us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
request-response:
t0: "2022-05-09T19:24:11.693"
t1: "2022-05-09T19:24:11.693"
t2: "2022-05-09T19:24:11.693"
delta (full): 111us
delta (self -> clock): 20us
delta (clock -> self): 91us
async:
t0: "2022-05-09T19:24:11.694"
t1: "2022-05-09T19:24:11.694"
delta: 16us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
request-response:
t0: "2022-05-09T19:24:12.277"
t1: "2022-05-09T19:24:12.277"
t2: "2022-05-09T19:24:12.277"
delta (full): 67us
delta (self -> clock): 51us
delta (clock -> self): 16us
async:
t0: "2022-05-09T19:24:12.278"
t1: "2022-05-09T19:24:12.278"
delta: 61us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
request-response:
t0: "2022-05-09T19:24:12.847"
t1: "2022-05-09T19:24:12.847"
t2: "2022-05-09T19:24:12.847"
delta (full): 40us
delta (self -> clock): 30us
delta (clock -> self): 10us
async:
t0: "2022-05-09T19:24:12.848"
t1: "2022-05-09T19:24:12.848"
delta: 44us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
request-response:
t0: "2022-05-09T19:24:13.390"
t1: "2022-05-09T19:24:13.390"
t2: "2022-05-09T19:24:13.390"
delta (full): 56us
delta (self -> clock): 46us
delta (clock -> self): 10us
async:
t0: "2022-05-09T19:24:13.391"
t1: "2022-05-09T19:24:13.391"
delta: 38us
@iMacWork: ~/workspace # master $ ./build/caf/release/examples/hello_world
request-response:
t0: "2022-05-09T19:24:13.963"
t1: "2022-05-09T19:24:13.963"
t2: "2022-05-09T19:24:13.963"
delta (full): 128us
delta (self -> clock): 118us
delta (clock -> self): 10us
async:
t0: "2022-05-09T19:24:13.963"
t1: "2022-05-09T19:24:13.963"
delta: 15us
Btw, CAF timestamps internally store nanosecond resolution. The system clock seems to have microsecond resolution. The timesamps only show milliseconds in the ISO-format, that's why they all look the same.
Farafonov Alexey
@farafonov-alexey
@Neverlord Thank's for measuring
I have this results
alexey@DESKTOP-2KI1PTN C:\Users\Alexey\Documents\caf-request-recieve\build-Release-msvc_2019_x86\bin>"C:/Users/Alexey/Documents/caf-request-recieve/build-Release-msvc_2019_x86/bin/console_caf.exe"
request-response:
t0: "2022-05-11T09:01:47.152"
t1: "2022-05-11T09:01:47.152"
t2: "2022-05-11T09:01:47.152"
delta (full): 195.5us
delta (self -> clock): 171.1us
delta (clock -> self): 24.4us
async:
t0: "2022-05-11T09:01:47.154"
t1: "2022-05-11T09:01:47.167"
delta: 12.1155ms
  alexey@DESKTOP-2KI1PTN C:\Users\Alexey\Documents\caf-request-recieve\build-Release-msvc_2019_x86\bin>"C:/Users/Alexey/Documents/caf-request-recieve/build-Release-msvc_2019_x86/bin/console_caf.exe"
request-response:
t0: "2022-05-11T09:03:42.867"
t1: "2022-05-11T09:03:42.867"
t2: "2022-05-11T09:03:42.867"
delta (full): 143.1us
delta (self -> clock): 107.9us
delta (clock -> self): 35.2us
async:
t0: "2022-05-11T09:03:42.869"
t1: "2022-05-11T09:03:42.871"
delta: 1.6837ms
alexey@DESKTOP-2KI1PTN C:\Users\Alexey\Documents\caf-request-recieve\build-Release-msvc_2019_x86\bin>"C:/Users/Alexey/Documents/caf-request-recieve/build-Release-msvc_2019_x86/bin/console_caf.exe"
request-response:
t0: "2022-05-11T09:03:44.086"
t1: "2022-05-11T09:03:44.087"
t2: "2022-05-11T09:03:44.087"
delta (full): 206.8us
delta (self -> clock): 191.5us
delta (clock -> self): 15.3us
async:
t0: "2022-05-11T09:03:44.089"
t1: "2022-05-11T09:03:44.090"
delta: 766.6us

alexey@DESKTOP-2KI1PTN C:\Users\Alexey\Documents\caf-request-recieve\build-Release-msvc_2019_x86\bin>"C:/Users/Alexey/Documents/caf-request-recieve/build-Release-msvc_2019_x86/bin/console_caf.exe"
request-response:
t0: "2022-05-11T09:03:45.375"
t1: "2022-05-11T09:03:45.376"
t2: "2022-05-11T09:03:45.376"
delta (full): 88.3us
delta (self -> clock): 70.6us
delta (clock -> self): 17.7us
async:
t0: "2022-05-11T09:03:45.378"
t1: "2022-05-11T09:03:45.389"
delta: 11.0762ms

alexey@DESKTOP-2KI1PTN C:\Users\Alexey\Documents\caf-request-recieve\build-Release-msvc_2019_x86\bin>"C:/Users/Alexey/Documents/caf-request-recieve/build-Release-msvc_2019_x86/bin/console_caf.exe"
request-response:
t0: "2022-05-11T09:03:46.646"
t1: "2022-05-11T09:03:46.646"
t2: "2022-05-11T09:03:46.646"
delta (full): 129.1us
delta (self -> clock): 106.2us
delta (clock -> self): 22.9us
async:
t0: "2022-05-11T09:03:46.648"
t1: "2022-05-11T09:03:46.655"
delta: 6.2401ms

alexey@DESKTOP-2KI1PTN C:\Users\Alexey\Documents\caf-request-recieve\build-Release-msvc_2019_x86\bin>"C:/Users/Alexey/Documents/caf-request-recieve/build-Release-msvc_2019_x86/bin/console_caf.exe"
request-response:
t0: "2022-05-11T09:03:47.915"
t1: "2022-05-11T09:03:47.915"
t2: "2022-05-11T09:03:47.915"
delta (full): 228.6us
delta (self -> clock): 200.6us
delta (clock -> self): 28us
async:
t0: "2022-05-11T09:03:47.918"
t1: "2022-05-11T09:03:47.920"
delta: 2.6073ms
Async timing bothers me) from 12ms to 700us
Dominik Charousset
@Neverlord
That is some variance right there!
Interesting. Is Windows your target platform?
Farafonov Alexey
@farafonov-alexey
We have armhf, linux x86, x64 and windows x86, x64
So yeah, Windows one of our target platforms
Dominik Charousset
@Neverlord
Do you see this behavior anywhere else besides Windows?
We don't have any Windows developer in our team and we do our benchmarks on Linux (and occasionally on macOS).
Farafonov Alexey
@farafonov-alexey
I just changed you code slightly
#include <iostream>
#include <string>

#include "caf/actor_ostream.hpp"
#include "caf/actor_system.hpp"
#include "caf/caf_main.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/timestamp.hpp"

using namespace caf;

using namespace std::literals;

behavior clock_actor() {
  return {[](get_atom) { return make_timestamp(); }};
}

void request(actor_system &sys, caf::actor &clk) {
  scoped_actor self{sys};
  auto t0 = make_timestamp();
  self->request(clk, 5s, get_atom_v)
      .receive(
          [&](timestamp t1) {
            auto t2 = make_timestamp();
            std::cout << "request-response:\n"
                      << "t0: " << caf::deep_to_string(t0) << '\n'
                      << "t1: " << caf::deep_to_string(t1) << '\n'
                      << "t2: " << caf::deep_to_string(t2) << '\n'
                      << "delta (full): " << caf::deep_to_string(t2 - t0)
                      << '\n'
                      << "delta (self -> clock): "
                      << caf::deep_to_string(t1 - t0) << '\n'
                      << "delta (clock -> self): "
                      << caf::deep_to_string(t2 - t1) << '\n';
          },
          [](const error &) {});
}
void caf_main(actor_system &sys) {
  // request-response
  auto clk = sys.spawn(clock_actor);
  request(sys, clk);
  request(sys, clk);
}

CAF_MAIN()
alexey@DESKTOP-2KI1PTN C:\Users\Alexey\Documents\caf-request-recieve\build-Release-msvc_2019_x86\bin>"C:/Users/Alexey/Documents/caf-request-recieve/build-Release-msvc_2019_x86/bin/console_caf.exe"
request-response:
t0: "2022-05-11T09:17:54.615"
t1: "2022-05-11T09:17:54.615"
t2: "2022-05-11T09:17:54.615"
delta (full): 192.8us
delta (self -> clock): 171.1us
delta (clock -> self): 21.7us
request-response:
t0: "2022-05-11T09:17:54.618"
t1: "2022-05-11T09:17:54.631"
t2: "2022-05-11T09:17:54.631"
delta (full): 12.5783ms
delta (self -> clock): 12.571ms
delta (clock -> self): 7.3us

alexey@DESKTOP-2KI1PTN C:\Users\Alexey\Documents\caf-request-recieve\build-Release-msvc_2019_x86\bin>"C:/Users/Alexey/Documents/caf-request-recieve/build-Release-msvc_2019_x86/bin/console_caf.exe"
request-response:
t0: "2022-05-11T09:18:29.041"
t1: "2022-05-11T09:18:29.041"
t2: "2022-05-11T09:18:29.041"
delta (full): 291.1us
delta (self -> clock): 262us
delta (clock -> self): 29.1us
request-response:
t0: "2022-05-11T09:18:29.044"
t1: "2022-05-11T09:18:29.059"
t2: "2022-05-11T09:18:29.059"
delta (full): 15.3228ms
delta (self -> clock): 15.3034ms
delta (clock -> self): 19.4us

alexey@DESKTOP-2KI1PTN C:\Users\Alexey\Documents\caf-request-recieve\build-Release-msvc_2019_x86\bin>"C:/Users/Alexey/Documents/caf-request-recieve/build-Release-msvc_2019_x86/bin/console_caf.exe"
request-response:
t0: "2022-05-11T09:20:10.114" 
t1: "2022-05-11T09:20:10.114" 
t2: "2022-05-11T09:20:10.114" 
delta (full): 282.5us
delta (self -> clock): 261.8us
delta (clock -> self): 20.7us 
request-response:
t0: "2022-05-11T09:20:10.117"   
t1: "2022-05-11T09:20:10.131"   
t2: "2022-05-11T09:20:10.131"   
delta (full): 14.1872ms
delta (self -> clock): 14.1695ms
delta (clock -> self): 17.7us 

alexey@DESKTOP-2KI1PTN C:\Users\Alexey\Documents\caf-request-recieve\build-Release-msvc_2019_x86\bin>"C:/Users/Alexey/Documents/caf-request-recieve/build-Release-msvc_2019_x86/bin/console_caf.exe"
request-response:
t0: "2022-05-11T09:20:26.313"
t1: "2022-05-11T09:20:26.313"
t2: "2022-05-11T09:20:26.313"
delta (full): 44.1us
delta (self -> clock): 30.7us
delta (clock -> self): 13.4us
request-response:
t0: "2022-05-11T09:20:26.315"   
t1: "2022-05-11T09:20:26.330"   
t2: "2022-05-11T09:20:26.330"   
delta (full): 14.5885ms
delta (self -> clock): 14.5775ms
delta (clock -> self): 11us
The second request call is way too longer

Do you see this behavior anywhere else besides Windows?

I'll check right now on linux

Farafonov Alexey
@farafonov-alexey
@Neverlord the same example on linux
alexey@alexey-ubuntu-proxmox:~/Documents/caf-request-recieve/build-Release-GCC_9.4.0/bin$ /home/alexey/Documents/caf-request-recieve/build-Release-GCC_9.4.0/bin/console_caf 
request-response:
t0: "2022-05-11T10:21:59.186"
t1: "2022-05-11T10:21:59.186"
t2: "2022-05-11T10:21:59.186"
delta (full): 117.954us
delta (self -> clock): 84.43us
delta (clock -> self): 33.524us
request-response:
t0: "2022-05-11T10:21:59.186"
t1: "2022-05-11T10:21:59.186"
t2: "2022-05-11T10:21:59.186"
delta (full): 50.254us
delta (self -> clock): 27.101us
delta (clock -> self): 23.153us
alexey@alexey-ubuntu-proxmox:~/Documents/caf-request-recieve/build-Release-GCC_9.4.0/bin$ /home/alexey/Documents/caf-request-recieve/build-Release-GCC_9.4.0/bin/console_caf 
request-response:
t0: "2022-05-11T10:22:00.525"
t1: "2022-05-11T10:22:00.526"
t2: "2022-05-11T10:22:00.526"
delta (full): 132.54us
delta (self -> clock): 110.649us
delta (clock -> self): 21.891us
request-response:
t0: "2022-05-11T10:22:00.526"
t1: "2022-05-11T10:22:00.526"
t2: "2022-05-11T10:22:00.526"
delta (full): 196.952us
delta (self -> clock): 186.492us
delta (clock -> self): 10.46us
alexey@alexey-ubuntu-proxmox:~/Documents/caf-request-recieve/build-Release-GCC_9.4.0/bin$ /home/alexey/Documents/caf-request-recieve/build-Release-GCC_9.4.0/bin/console_caf 
request-response:
t0: "2022-05-11T10:22:01.859"
t1: "2022-05-11T10:22:01.859"
t2: "2022-05-11T10:22:01.859"
delta (full): 29.535us
delta (self -> clock): 16.872us
delta (clock -> self): 12.663us
request-response:
t0: "2022-05-11T10:22:01.859"
t1: "2022-05-11T10:22:01.859"
t2: "2022-05-11T10:22:01.859"
delta (full): 40.927us
delta (self -> clock): 14.096us
delta (clock -> self): 26.831us
Dominik Charousset
@Neverlord
That's pretty much in line with the results I've seen.
Farafonov Alexey
@farafonov-alexey
But right now I'm working on windows x86 library :'(
Dominik Charousset
@Neverlord
Did you try the sharing scheduler? Maybe that one performs better on Windows in the meantime (until figuring out what Windows doesn't like about the default scheduler).