UVM ports: put,get,export, analysis - port

I am trying to master in UVM, and completely lost in UVM ports. Please help better understand the ports.
So as I understood there are 3 main types of ports
Put-> get : producer put data and consumer gets the data. This is blocking statement.
Put-> Export->Imp
Analysis->Subscriber : producer transmit the data and other subscribers gets it. This is non-blocking statement.
Also there are TLM_FIFOs which allows to buffer the transaction for later usage. It has 2 types: uvm_tlm_fifo and uvm_tlm_analysis_fifo.
And my questions are:
Is my understanding right?
What is the difference between get and export?
What is the difference between uvm_tlm_fifo and uvm_tlm_analysis_fifo?
Thanks
Hayk

The use of TLM interfaces isolates each component from changes in
other components throughout the environment.
For ports understanding, there are two common terminologies: Producer and Consumer. Instead of producer and consumer, think in terms of initiator and target of communication between components.
An initiator is always having a port connected to it. Just like driver has seq_item_port.
A target always have an export. Just like sequencer havng seq_item_export.
For Put/Get ports:
Initiator/Producer:
port.put(tr);
Target/Consumer: (Note the Input in task)
task pet(input simple_trans t);
//...
endtask
In put port, initiator is the producer which puts a transaction for the consumer. Initiator/Producer blocks till the put task is unblocked by Target/Consumer.
Initiator/Consumer:
port.get(tr);
Target/Producer:(Note the Output in task)
task get(output simple_trans t);
//...
endtask
While in get port, the initiator is the consumer. A consumer requests/asks for transaction and producer provides it. Initiator/Consumer blocks till the get task is unblocked by Target/Producer.
The put/get ports are typically used to have operational behavior of a system. These ports are used for one-to-one communication.
Analysis ports are generally used to broadcast the transaction. The write method is always non blocking. There may be zero or more connections to analysis ports. Again the rules for initiator and target remains the same.
Initiator:
port.write(tr);
Target:(Note the function, not task)
function void write(simple_trans tr);
//...
endfunction
All the ports requires implementation of methods in user's classes. The uvm_*_imp is used for the same. While buffering of data can be done through FIFOs.
For analysis ports, uvm_analysis_fifo is used, since these FIFO must have the ability to further broadcast the transaction. The default size of analysis FIFO is unbounded.
While uvm_tlm_fifo is used when put/get ports are used, that is, for one-to-one communication. The default size of analysis FIFO is 1, which can be changed to unbounded.
Again, FIFOs always puts/gets the data upon request from a component, henceforth there is an export type of connection at both the ends.
For further information, refer to UVM User Guide.

Related

TFF: Remote Executor

We are setting up a federated scenario with Server and Client on different physical machines.
On the server, we have used the docker container to kickstart:
The above has been borrowed from Kubernetes tutorial. We believe this creates a 'local executor' [Ref 1] which helps create a gRPC server [Ref 2].
Ref 1:
Ref 2:
Next on the client 1, we are calling tff.framework.RemoteExecutor that connects to the gRPC server.
Our understanding based on the above is that the Remote Executor runs on the client which connects to the gRPC server.
Assuming the above is correct, how can we send a
tff.tf_computation
from the server to the client and print the output on the client side to ensure the whole setup works well.
Your understanding is definitely correct.
If you construct an ExecutorFactory directly, as seems to be the case in the code above, passing it to tff.framework.set_default_context will install your remote stack as the default mechanism for executing computations in the TFF runtime. You should additionally be able to pass the appropriate channels to tff.backends.native.set_remote_execution_context to handle the remote executor construction and context installation if desired, but the way you are doing it certainly works, and allows for greater customization.
Once you have set this up, running an example end-to-end should be fairly simple. We will set up a computation which takes a set of federated integers, prints on the clients, and sums the integers up. Let:
#tff.tf_computation(tf.int32)
def print_and_return(x):
# We must use tf.print here, as this logic will be
# serialized and run on the clients as TensorFlow.
tf.print('hello world')
return x
#tff.federated_computation(tff.FederatedType(tf.int32, tff.CLIENTS))
def print_and_sum(federated_arg):
same_ints = tff.federated_map(print_and_return, federated_arg)
return tff.federated_sum(same_ints)
Suppose we have N clients; we simply instantiate the set of federated integers, and invoke our computation.
federated_ints = [1] * N
total = print_and_sum(federated_ints)
assert total == N
This should cause the tf.prints defined above to run on the remote machine; as long as tf.print is directed to an output stream which you can monitor, you should be able to see it.
PS: you may note that the federated sum above is unnecessary; it certainly is. The same effect can be had by simply mapping the identity function with the serialized print.

ROS - How do I publish a message and get the subscribed callback immediately

I have a ROS node that allows you to "publish" a data structure to it, to which it responds by publishing an output. The timestamp of what I published and what it publishes is matched.
Is there a mechanism for a blocking function where I send/publish and output, and it waits until I receive an output?
I think you need the ROS_Services (client/server) pattern instead of the publisher/subscriber.
Here is a simple example to do that in Python:
Client code snippet:
import rospy
from test_service.srv import MySrvFile
rospy.wait_for_service('a_topic')
try:
send_hi = rospy.ServiceProxy('a_topic', MySrvFile)
print('Client: Hi, do you hear me?')
resp = send_hi('Hi, do you hear me?')
print("Server: {}".format(resp.response))
except rospy.ServiceException, e:
print("Service call failed: %s"%e)
Server code snippet:
import rospy
from test_service.srv import MySrvFile, MySrvFileResponse
def callback_function(req):
print(req)
return MySrvFileResponse('Hello client, your message received.')
rospy.init_node('server')
rospy.Service('a_topic', MySrvFile, callback_function)
rospy.spin()
MySrvFile.srv
string request
---
string response
Server out:
request: "Hi, do you hear me?"
Client out:
Client: Hi, do you hear me?
Server: Hello client, your message received.
Learn more in ros-wiki
Project repo on GitHub.
[UPDATE]
If you are looking for fast communication, TCP-ROS communication is not your purpose because it is slower than a broker-less communicator like ZeroMQ (it has low latency and high throughput):
ROS-Service pattern equivalent in ZeroMQ is REQ/REP (client/server)
ROS publisher/subscriber pattern equivalent in ZeroMQ is PUB/SUB
ROS publisher/subscriber with waitformessage equivalent in ZeroMQ is PUSH/PULL
ZeroMQ is available in both Python and C++
Also, to transfer huge amounts of data (e.g. pointcloud), there is a mechanism in ROS called nodelet which is supported only in C++. This communication is based on shared memory on a machine instead of TCP-ROS socket.
What exactly is a nodelet?
Since you want to stick with publish/ subscribers, assuming from your comment, that services are to slow I would have a look at waitForMessage (Documentation).
And for an example on how to use it you can have a look at this ros answers question.
All you need to do is to publish your data and immediately call waitForMessage on the output topic and manually pass the received message to your "callback".
I hope this is what you were looking for.
To get this request/reply behaviour ROS has a mechanism called ROS service.
You can specify the input and output of your service in a service file similar to a ROS message definition. You can then call the service of a node with your input and the call will receive an output when the service is finished.
Here is a tutorial how to use this mechanism in python. If you prefer C++ there is also one, you should find it.

Re-using Bigtable connection with AbstractCloudBigtableTableDoFn

I have a DoFn that extends AbstractCloudBigtableTableDoFn<> in order to send frequent Buffered Mutation requests to Bigtable.
When I run the job in the Cloud, I see repeated log entries at this step of the Dataflow pipeline that look like this:
Opening connection for projectId XXX, instanceId XXX, on data host batch-bigtable.googleapis.com, table admin host bigtableadmin.googleapis.com...
and
Bigtable options: BigtableOptions{XXXXX (lots of option entries here}
The code within the DoFn looks something like this:
#ProcessElement
public void processElement(ProcessContext c)
{
try
{
BufferedMutator mPutUnit = getConnection().getBufferedMutator(TableName.valueOf(TABLE_NAME));
for (CONDITION)
{
// create lots of different rowsIDs
Put p = new Put(newRowID).addColumn(COL_FAMILY, COL_NAME, COL_VALUE);
mPutUnit.mutate(p);
}
mPutUnit.close();
} catch (IOException e){e.printStackTrace();}
c.output(0);
}
This DoFn gets called very frequently.
Should I worry that Dataflow tries to re-establish the connection to Bigtable with every call to this DoFn? I was under the impression that inheriting from this class should ensure that a single connection to Bigtable should be re-used across all calls?
"Opening connection for projectId ..." should appear once per worker per AbstractCloudBigtableTableDoFn instance. Can you double check that connections are being opened per call as opposed to per worker?
Limit the number of workers to a handful
In stack driver, expand the "Opening connection for projectId" messages and check if jsonPayload.worker is duplicated across different log messages.
Also, can you detail what version of the client you are using and what version of beam?
Thanks!
To answer your questions...
Yes, you should be worried that Dataflow tries to reestablish a connection to Bigtable with each call to the DoFn. The expected behavior of AbstractCloudBigtableDoFn is that a Connection instance is maintained per worker.
No, inheriting from AbstractCloudBigtableDoFn does not ensure a single Connection instance is reused for each call to the DoFn. This is not possible because the DoFn is serialized across multiple physical machines based on the number of workers allocated for the Dataflow job.
First, ensure that there are no connection/authentication issues to Bigtable. Occasionally, Dataflow will need to reestablish a connection to Bigtable. However, doing so for each call to the DoFn is not expected.

Do I need to start multiple server-side workers for just a handful of ZeroMQ clients?

I am using Chumak in erlang, opening a ROUTER socket.
I have a handful (4 or so) clients that use the Python zmq library to send REQ requests to this server.
Things work fine most of the time, but sometimes a client will have disconnect issues (reconnecting automatically is in the client code, and it works). I've found that when an error occurs in one client connection, it seems to move on to others as well, and I get a lot of
** {{noproc,{gen_server,call,[<0.31596.16>,incomming_queue_out]}},
on the server.
On the server side, I'm just opening one chumak socket and looping:
{ok, Sock} = chumak:socket( router ),
{ok, _} = chumak:bind( Sock, tcp, "0.0.0.0", ?PORT ),
spawn_link( fun() -> loop( Sock ) end ),
...
loop( CmdSock ) ->
{ok, [Identity, <<>>, Data]} = chumak:recv_multipart( Sock ),
...
The ZeroMQ docs seem to imply that one listening socket is enough unless I have many clients.
Do I misunderstand them?
No, there is no need to increase number of Socket instances
Abstractions are great to reduce a need to understand all the details under the hood for a typical user. That ease of life stops whenever such user has to go into performance tuning or debugging incidents.
Let's step in this way:
- unless some mastodon beast sized data payloads are to get moved through, there is quite enough to have a single ROUTER-AccessPoint into a Socket-instance, for say tens, hundreds, thousands of REQ-AccessPoints on the client side(s).
- yet, such numbers will increase the performance envelope requirements for the ROUTER-side Context-instance, so as to remain capable of handling all the Scalable Formal Communication Archetype ( pre-scribed ) handling, so as to all happen in due time and fair fashion.
This means, one can soon realise benefits from spawning Context-instances with more than its initial default solo-thread + in all my high-performance setups I advocate for using zmq.AFFINITY mappings, so as to squeeze indeed a max performance on highest-priority Socket-instances, whereas leaving non-critical resources sharing a common sub-set of the Context-instance's IO-thread-pool.
Next comes RAM
Yes, the toys occupy memory.
Check all the .{RCV|SND}BUF, .MAXMSGSIZE, .{SND|RCV}HWM, .BACKLOG, .CONFLATE
Next comes LINK-MANAGEMENT
Do not hesitate to optimise .IMMEDIATE, .{RCV|SND}BUF, .RECONNECT_IVL, .RECONNECT_IVL_MAX, .TCP_KEEPALIVE, .TCP_KEEPALIVE_CNT, .TCP_KEEPALIVE_INTVL, .TCP_KEEPALIVE_IDLE
Always set .LINGER right upon instantiations, as drop-outs cease to be lethal.
Next may come a few defensive and performance helper tools:
.PROBE_ROUTER, .TCP_ACCEPT_FILTER, .TOS, .HANDSHAKE_IVL
Next step?
If no memory-related troubles remain in the game and once mentioning reconnections, my suspect would be to rather go and setup .IMMEDIATE + possibly let ROUTER benefit from explicit PROBE_ROUTER signalling.

TTcpServer remote connection to service

i need win XP service with TTcpServer.
application was created by "File->New->Other->ServiceApplication"
TTcpServer.localport := 33000
server registered with exename.exe /install
everything looks good, even netstat -a shows that port 33000 - LISTENING
but i can`t access that port from outside of this machine. only local.
and when i make the standard application with same params - all ok.
EDIT1
TTcpServe.OnAccept =
procedure TFlexorXL.tcpServerAccept(Sender: TObject;
ClientSocket: TCustomIpClient);
var str: string;
begin
if ClientSocket.Connect then
begin
str := ClientSocket.Receiveln;
ClientSocket.Sendln('test');
//ClientSocket.Disconnect;
end;
end;
TCP/IP works just fine in a service (I use it all the time), so you are likely just misusing the TTcpServer component (which is possible, because it is a horribly written component).
If the TTcpServer.LocalHost property is blank then the socket will bind to all available local IPv4 addresses, otherwise it will bind only to the particular IPv4 address that you specify (netstat will show you the actual IP that the server is actually bound to). That is the IP that you must have clients connect to. In the case of 0.0.0.0, you can connect to any IP that belongs to the server's machine.
With that said, in order to actually accept clients, you must either:
set the TTcpServer.BlockMode property to bmThreadBlocking. The server will then use an internal worker thread to accept connections, and each client will run in its own worker thread. However, you must perform all of your client-related logic inside of the TTcpServer.OnAccept event, because a client will be disconnected immediately after that event handler exits.
for any other value of BlockMode, you must call TTcpServer.Accept() yourself, such as in a timer or thread. If you call the overloaded version of Accept() that has no parameters, you must perform all of your client-related logic inside of the TTcpServer.OnAccept event, because the client will be disconnected immediately after that event handler exits. If you call the other overloaded version of Accept() that returns a TCustomIpClient object, then you control the lifetime of that object and can use it however you need.
With that said, if you are doing all of that, and still having problems, then you need to provide more information about your actual TTcpServer setup, show some actual TTcpServer code, etc. As it currently stands, you have not provides enough details to diagnose your problem.

Resources