Runtime division of variables in p4

Hi,

Is there a way to perform division of two int<w> or bit<w> metadata variables during runtime in p4?

I understand that the operations on arbitrary-precision integer int type variables need the values during the compile time. Also, the division operation is not listed for fixed-width signed or unsigned integers in the documentation.

Is there a way to circumvent this and preform division during runtime?

Applesoft BASIC on an Apple II in 1980 had floating point operations. The hardware had no floating-point unit, only 8-bit add, subtract, shift, and compare instructions. Thus if you have those operations, it is possible to build integer division operations out of them, as well as floating-point. That doesn’t mean it is fun to do. It can be very tedious and time-consuming, and it can require many such simpler operations to correctly perform a more complex operation, so it might not be a cost-effective exercise to try to do this on a hardware target that doesn’t already have hardware support for the operation you want.

Most people, when they see such limitations, tend to try to find approximate solutions that work well enough for the application at hand, rather than try to do the more general operations, e.g. limiting multiplication and division on integers where the divisor is a power of 2 means you can do integer shifts instead.

This article does not directly address your question, but may have some ideas you find useful, and/or its reference to the book Hacker’s Delight: p4-guide/floating-point-operations.md at master · jafingerhut/p4-guide · GitHub

Thank you very much for the response, @andyfingerhut.

For division operations involving certain feature of the incoming packet like payload size, which is beyond any kind of approximations to nearest power to 2, there is no way to achieve desired results even by coding it the tedious way, correct? As p4 code needs the numerical values at compile time, which we possibly can’t have ahead of time.

I am just trying to make sure I understand the limitation correctly.

Thank you once again!

What are you trying to calculate that requires a division, and why? Depending upon the purpose for which integer division is the obvious answer, there might be non-obvious approximations or techniques that you have not yet considered.

I am trying to calculate flow features for a flow between two hosts in the network. For example, i am trying to calculate the ratio of number of packets from (src to dst) to (dest to src) in a flow, based on which a match action table will be applied for that packet.

So you want to calculate (num_packets_from_A_to_B / num_packets_from_B_to_A), and then use the answer as a key in a table?

How precise of an answer do you need? e.g. is an answer like the following precise enough for your purposes?

“if the precise answer is >= 1, then round off to the nearest integer, and if the precise answer is <= 1, then round off to the nearest value of 1/N for some integer N”

Or perhaps even N could be restricted to a power of 2?

Or do you believe you need to know the answer more precisely than that? If so, how precise?

I am counting the packets using the bloom filter for each pair, that is, one entry for (A to B) and (B to A), and trying to find the ratio for every packet processed in the ingress pipeline. Then I use the answer to find a match in a table. Either to drop or forward. For example, in a very rudimentary way, if the ratio is in 1000s or 0.001, the flow is skewed and might denote some kind of an attack, then I drop the future packets from that particular source. If it is a normal traffic pattern, I forward.

I don’t need a precise value, approximate value is good enough.

The you can probably find the first 1 bit in each number and approximate that as the (log of) number’s size.
Notice that shifting by a variable amount can be very expensive in some architectures, so probably a lookup-table based approach is best.

Another technique would be something like this:

if ((counter1 >> 10) > counter2) {
    // code here that you want to execute if counter1 is greater than 1024*counter2
} else if ((counter2 >> 10) > counter1) {
    // code here that you want to execute if counter2 is greater than 1024*counter1
} else {
    // code here that you want to execute if counter1 and counter2 are at most a factor of 1024 different from each other
}

Thank you very much @andyfingerhut. That will work for my implementation. One last question, out of curiosity, the shift count here, which is 10, should be available during compile time right? Can we set its value from a table during runtime?

Shifts with constant values are cheap in hardware, but shifts with dynamic values can be very expensive.
It really depends on your target. Barrel shifter - Wikipedia

Some P4 targets might allow the shift amount to be a run-time variable, but at least some do not.
If they do not, it is straightforward to implement a variable length shift with a P4 table like this one: p4app-switchML/bitmap_checker.p4 at main · p4lang/p4app-switchML · GitHub