From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

High processor usage with C# and DAQmx

I'm looking to move our C++/Traditional nidaq code to C# and DAQmx.  I'm using VC# Express edition.  I have written a quick up which does synchronised waveform generation and analog acquisition running on a 6052E card.  I have synchronised the 2 by setting the signal source for the input channel to "ao/SampleClock".  I'm running the card nearly flat out at 300KS/s but only gettting called back once per second (continuous acquisition) with 300000 samples each time.  The processor usage on a P4 2.8GHz with hyperthreading is over 50% throughout the acquisition.  I'm doing basically nothing inside the read callback (although it is synchornised via the form's synchronisation object).  Am I doing something stupid here?  Code posted below.  It is a WinForms app which has 2 buttons (m_StartButton and m_StopButton) a label (m_TimingLabel) and a progress bar (m_ProgressBar).  I have disabled updating the label and progress bar inside the callback but that makes no difference so doesn't appear to be affecting performance.

(I'll add the code in a separate post as I can't exceed 5000 characters here)

Is this just a problem of using managed code and DAQmx?  We run the card this hard on lower PCs using traditional nidaq and see basically no processor usage.

All help is greatly appreciated.

Cheers

Russell
0 Kudos
Message 1 of 21
(5,035 Views)
Here is the function that starts tha acquisition

            m_InputTask = new Task("ScanDelay Input");
            m_OutputTask = new Task("ScanDelay Output");

            m_InputTask.AIChannels.CreateVoltageChannel(
                "Dev1/ai0",
                "",
                AITerminalConfiguration.Differential,
                -1,
                1,
                AIVoltageUnits.Volts);

            m_OutputTask.AOChannels.CreateVoltageChannel(
                "Dev1/ao0",
                "",
                -1,
                1,
                AOVoltageUnits.Volts);

            m_InputTask.Timing.ConfigureSampleClock(
                "ao/SampleClock",
                m_SampleRate,
                SampleClockActiveEdge.Rising,
                SampleQuantityMode.ContinuousSamples);

            Double[] SquareWave = new Double[10] { -1, -1, -1, -1, -1, 1, 1, 1, 1, 1 };

            m_OutputTask.Timing.ConfigureSampleClock(
                "",
                m_SampleRate,
                SampleClockActiveEdge.Rising,
                SampleQuantityMode.ContinuousSamples,
                SquareWave.Length);

            m_InputTask.Control(TaskAction.Verify);
            m_OutputTask.Control(TaskAction.Verify);

            m_Writer = new AnalogSingleChannelWriter(m_OutputTask.Stream);
            m_Writer.WriteMultiSample(false, SquareWave);

            m_StartButton.Enabled = false;
            m_StopButton.Enabled = true;

            m_Count = 0;
            m_InputCallback = new AsyncCallback(OnData);
            m_Reader = new AnalogSingleChannelReader(m_InputTask.Stream);
            m_Reader.SynchronizingObject = this;
            m_Reader.BeginReadMultiSample(m_SamplesPerAq, m_InputCallback, null);

            m_OutputTask.Start();
            m_LastTime = DateTime.Now;

0 Kudos
Message 2 of 21
(5,015 Views)
Here are the constants:

        private const Int32 m_SampleRate        = 300000;
        private const Int32 m_CallbacksPerSec   = 1;
        private const Int32 m_SamplesPerAq      = m_SampleRate / m_CallbacksPerSec;
        private const Int32 m_NumSecs           = 20;
        private const Int32 m_NumAqs            = m_CallbacksPerSec * m_NumSecs;

And here is the callback function

        private void OnData(IAsyncResult ar)
        {
            ++m_Count;
            m_Data = m_Reader.EndReadMultiSample(ar);
            m_ProgressBar.Value = (m_Count * 100) / m_NumAqs;
            TimeSpan Time = DateTime.Now - m_LastTime;
            m_TimingLabel.Text = Time.ToString();
            m_LastTime = DateTime.Now;
            if (m_Count < m_NumAqs)
            {
                m_Reader.BeginReadMultiSample(m_SamplesPerAq, m_InputCallback, null);
            }
            else
            {
                Stop();
            }
        }

Thanks Russell
0 Kudos
Message 3 of 21
(5,009 Views)
I've now written the same code in Borland C++Builder using the ANSI C interface to DAQmx and I see only 6-8% processor usage.  Does this mean the .Net interface is just really inefficient?  The only difference between the 2 lots of code is that the C interface has to use DAQmxRegisterEveryNSamplesEvent rather than async callbacks. 

We'd really like to move to C# but this issue will stop us.  Anyone any ideas?

Thanks

Russell
0 Kudos
Message 4 of 21
(4,993 Views)
Ok, to make things more interesting, I've written C# code to use the C API to DAQmx rather than the .Net API (basically simulates the DAQmx.Net interface so the code looks similar) but now uses the EveryNSamples callback rather than asynchronous I/O and the processor usage is basically identical to using C++ and the C Interface.

This is odd.  Does anyone have a clue as to why DAQmx.Net is so processor intensive when obviously the underlying driver isn't?  At the moment, I'm basically re-producing all the DAQmx.Net class structure for the bit I use, but using P/Invoke to call the C API interface to get reasonable performance but this doesn't look like something we should have to do.

Thanks

Russell
0 Kudos
Message 5 of 21
(4,982 Views)
Hi Russell,
 
Thanks for your post on the Discussion forums I have been looking at another similar discussion that might be of interest to you:
 
 
I hope this helps!
 
Kurt
0 Kudos
Message 6 of 21
(4,984 Views)
Essentially what version of DAQ MX are you working with?
Kurt
0 Kudos
Message 7 of 21
(4,980 Views)
Thanks, but the problem was slightly different.  The C API interface to DAQmx doesn't have the BeginRead... asynchronouse methods and so you have to set up a callback and then use the synchrous reads if you don't want the processor tied up.

My problem is that the asynchronous reads provided in the .Net interface seem extremely inefficient as opposed to the callback mechanism provided in the C Interface.

Cheers

Russell
0 Kudos
Message 8 of 21
(4,983 Views)
Version 8.0 from C# express 2005 (so it is .Net 2.0 app, but I understand the DAQmx libraries are .net 1.1.  Is there an issue using a 1.1 assembly from 2.0?)

Thanks

Russell
0 Kudos
Message 9 of 21
(4,977 Views)
Hi Russell,

This is a strange issue.  Visual C# Express installs with the .NET 2.0 framework, but the DAQmx libraries were written for the 1.1 framework.  However, if the DAQmx libraries need the 1.1 framework, there should be 1.1 assemblies installed along side the 2.0 assemblies.  So, I do not think it is the source of the problem.  I would expect to see an error if that was the problem.

Would you mind posting your project, so that I may attempt to replicate the issue?  It would be much easier for NI to figure out what may be causing the problem.  Another suggestion I had is to set the sampling rate to something much lower such as 10,000Hz or even 1,000Hz.  If you notice different behavior, then we know the problem may be related to the high sampling rate with the asynchronous callback.

Thanks,

Tyler Tigue
Applications Engineer
National Instruments


Message Edited by Tyler T. on 01-27-2006 03:25 PM

0 Kudos
Message 10 of 21
(4,959 Views)