Re: [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am 05.01.2014 22:25, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 22:02:40 +0100
> Frank Schäfer <fschaefer.oss@xxxxxxxxxxxxxx> escreveu:
>
>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>> From: Mauro Carvalho Chehab <mchehab@xxxxxxxxxx>
>> Is this line still correct ? ;)
>>
>>> Instead of allocating/deallocating URBs and transfer buffers
>>> every time stream is started/stopped, just do it once.
>>>
>>> That reduces the memory allocation pressure and makes the
>>> code that start/stop streaming a way simpler.
>>>
>>> Signed-off-by: Mauro Carvalho Chehab <mchehab@xxxxxxxxxx>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@xxxxxxxxxxx>
>> Two Signed-off-by lines ? ;)
>>
>>> ---
>>>  drivers/media/usb/em28xx/em28xx-audio.c | 128 ++++++++++++++++++--------------
>>>  1 file changed, 73 insertions(+), 55 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
>>> index e5120430ec80..30ee389a07f0 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
>>> @@ -3,7 +3,7 @@
>>>   *
>>>   *  Copyright (C) 2006 Markus Rechberger <mrechberger@xxxxxxxxx>
>>>   *
>>> - *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@xxxxxxxxxx>
>>> + *  Copyright (C) 2007-2014 Mauro Carvalho Chehab
>>>   *	- Port to work with the in-kernel driver
>>>   *	- Cleanups, fixes, alsa-controls, etc.
>>>   *
>>> @@ -70,16 +70,6 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
>>>  			usb_kill_urb(urb);
>>>  		else
>>>  			usb_unlink_urb(urb);
>>> -
>>> -		usb_free_coherent(dev->udev,
>>> -				  urb->transfer_buffer_length,
>>> -				  dev->adev.transfer_buffer[i],
>>> -				  urb->transfer_dma);
>>> -
>>> -		dev->adev.transfer_buffer[i] = NULL;
>>> -
>>> -		usb_free_urb(urb);
>>> -		dev->adev.urb[i] = NULL;
>>>  	}
>>>  
>>>  	return 0;
>>> @@ -174,53 +164,14 @@ static void em28xx_audio_isocirq(struct urb *urb)
>>>  static int em28xx_init_audio_isoc(struct em28xx *dev)
>>>  {
>>>  	int       i, errCode;
>>> -	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
>>> -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>>  
>>>  	dprintk("Starting isoc transfers\n");
>>>  
>>> +	/* Start streaming */
>>>  	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>> -		struct urb *urb;
>>> -		int j, k;
>>> -		void *buf;
>>> -
>>> -		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
>>> -		if (!urb) {
>>> -			em28xx_errdev("usb_alloc_urb failed!\n");
>>> -			for (j = 0; j < i; j++) {
>>> -				usb_free_urb(dev->adev.urb[j]);
>>> -				kfree(dev->adev.transfer_buffer[j]);
>>> -			}
>>> -			return -ENOMEM;
>>> -		}
>>> -
>>> -		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
>>> -					 &urb->transfer_dma);
>>> -		if (!buf)
>>> -			return -ENOMEM;
>>> -		dev->adev.transfer_buffer[i] = buf;
>>> -		memset(buf, 0x80, sb_size);
>>> -
>>> -		urb->dev = dev->udev;
>>> -		urb->context = dev;
>>> -		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
>>> -		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
>>> -		urb->transfer_buffer = dev->adev.transfer_buffer[i];
>>> -		urb->interval = 1;
>>> -		urb->complete = em28xx_audio_isocirq;
>>> -		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
>>> -		urb->transfer_buffer_length = sb_size;
>>> -
>>> -		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
>>> -			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
>>> -			urb->iso_frame_desc[j].offset = k;
>>> -			urb->iso_frame_desc[j].length =
>>> -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>> -		}
>>> -		dev->adev.urb[i] = urb;
>>> -	}
>>> +		memset(dev->adev.transfer_buffer[i], 0x80,
>>> +		       dev->adev.urb[i]->transfer_buffer_length);
>>>  
>>> -	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>>  		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
>>>  		if (errCode) {
>>>  			em28xx_errdev("submit of audio urb failed\n");
>>> @@ -643,13 +594,36 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
>>>  	.page      = snd_pcm_get_vmalloc_page,
>>>  };
>>>  
>>> +static void em28xx_audio_free_urb(struct em28xx *dev)
>>> +{
>>> +	int i;
>>> +
>>> +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>> +		struct urb *urb = dev->adev.urb[i];
>>> +
>>> +		if (!dev->adev.urb[i])
>>> +			continue;
>>> +
>>> +		usb_free_coherent(dev->udev,
>>> +				  urb->transfer_buffer_length,
>>> +				  dev->adev.transfer_buffer[i],
>>> +				  urb->transfer_dma);
>>> +
>>> +		usb_free_urb(urb);
>>> +		dev->adev.urb[i] = NULL;
>>> +		dev->adev.transfer_buffer[i] = NULL;
>>> +	}
>>> +}
>>> +
>>>  static int em28xx_audio_init(struct em28xx *dev)
>>>  {
>>>  	struct em28xx_audio *adev = &dev->adev;
>>>  	struct snd_pcm      *pcm;
>>>  	struct snd_card     *card;
>>>  	static int          devnr;
>>> -	int                 err;
>>> +	int                 err, i;
>>> +	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
>>> +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>>  
>>>  	if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
>>>  		/* This device does not support the extension (in this case
>>> @@ -662,7 +636,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>  
>>>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>>>  			 "Rechberger\n");
>>> -	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
>>> +	printk(KERN_INFO
>>> +	       "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
>>>  
>>>  	err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
>>>  			      &card);
>>> @@ -704,6 +679,47 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>  		em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
>>>  	}
>>>  
>>> +	/* Alloc URB and transfer buffers */
>>> +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>> +		struct urb *urb;
>>> +		int j, k;
>>> +		void *buf;
>>> +
>>> +		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
>>> +		if (!urb) {
>>> +			em28xx_errdev("usb_alloc_urb failed!\n");
>>> +			em28xx_audio_free_urb(dev);
>>> +			return -ENOMEM;
>>> +		}
>>> +		dev->adev.urb[i] = urb;
>>> +
>>> +		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
>>> +					 &urb->transfer_dma);
>>> +		if (!buf) {
>>> +			em28xx_errdev("usb_alloc_coherent failed!\n");
>>> +			em28xx_audio_free_urb(dev);
>>> +			return -ENOMEM;
>>> +		}
>>> +		dev->adev.transfer_buffer[i] = buf;
>>> +
>>> +		urb->dev = dev->udev;
>>> +		urb->context = dev;
>>> +		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
>>> +		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
>>> +		urb->transfer_buffer = dev->adev.transfer_buffer[i];
>>> +		urb->interval = 1;
>>> +		urb->complete = em28xx_audio_isocirq;
>>> +		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
>>> +		urb->transfer_buffer_length = sb_size;
>>> +
>>> +		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
>>> +			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
>>> +			urb->iso_frame_desc[j].offset = k;
>>> +			urb->iso_frame_desc[j].length =
>>> +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>> +		}
>>> +	}
>>> +
>>>  	err = snd_card_register(card);
>>>  	if (err < 0) {
>>>  		snd_card_free(card);
>>> @@ -728,6 +744,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>>  		return 0;
>>>  	}
>>>  
>>> +	em28xx_audio_free_urb(dev);
>>> +
>>>  	if (dev->adev.sndcard) {
>>>  		snd_card_free(dev->adev.sndcard);
>>>  		dev->adev.sndcard = NULL;
>> I don't get it.
>> How does this patch reduce the memory allocation pressure ?
>> You are still allocating the same amount of memory.
> True, but it is not de-allocating/reallocating the same amount of
> memory every time, for every start/stop trigger. Depending on the
> userspace and the amount of available RAM, this could cause memory 
> fragmentation.
>
> If you take a look at xHCI logs, you'll see that those operations
> are very expensive, and that it occurs too often.
How often is the device started/stopped ?
It's nothing that happens often/with a high freuqency, so is memeory
fragmentation really a problem here ?

>
>> The only differences is that you already do this when the device isn't
>> used yet and don't free it when gets unused again.
>> IMHO that makes things worse, not better.
> Why is it worse?
Because you increase the memory usage of closed devices.

> FYI, we're currently allocating DVB buffers at the device init too,
> due to the memory fragmentation problems. This is actually critical
> if you try to use it on an ARM with limited amount of RAM.
I was always wondering why.

Ok, if this really solves problems on ARM, do it.
I assume it makes sense fix it for analog video, too. ;)

>
>> And yes, it makes the code that starts/stops streaming a way simpler.
>> But at the same time it makes the module initialization code the same
>> amount more complicated.
>
>

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux