Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. making a text box more efficient

making a text box more efficient

Scheduled Pinned Locked Moved C#
csharpquestion
29 Posts 6 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    codie3007
    wrote on last edited by
    #1

    Hi, In my form based C# app, I use one (of many) option of logging/writing program steps to a text box on the form. It works ok for a while and then starts to slow down as more and more data is passed to it. Is there a way to make this more efficient ? Thanks in advance.

    D L A 3 Replies Last reply
    0
    • C codie3007

      Hi, In my form based C# app, I use one (of many) option of logging/writing program steps to a text box on the form. It works ok for a while and then starts to slow down as more and more data is passed to it. Is there a way to make this more efficient ? Thanks in advance.

      D Offline
      D Offline
      Dave Kreskowiak
      wrote on last edited by
      #2

      It slows down because you've added a large amount of data to the String that it's showing you. Strings are immutable in .NET, so every time you add data to it, an entirely new string has to be created with the old data copied to it and the new data appended to the end. The answer is simple. Don't use a TextBox. A common replacement for this particular use is a ListBox.

      A guide to posting questions on CodeProject[^]
      Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
           2006, 2007, 2008
      But no longer in 2009...

      A 1 Reply Last reply
      0
      • C codie3007

        Hi, In my form based C# app, I use one (of many) option of logging/writing program steps to a text box on the form. It works ok for a while and then starts to slow down as more and more data is passed to it. Is there a way to make this more efficient ? Thanks in advance.

        L Offline
        L Offline
        Luc Pattyn
        wrote on last edited by
        #3

        as Dave said, a ListBox is the preferred Control for showing line-oriented textual information. It would be happy holding thousands of lines of text for you, and continue accepting lots more, whereas a TextBox would come to a stand still. Using TextBox.AppendText("someMore") is slightly better than using TextBox.Text+="someMore", but it too suffers from the quadratic cost explosion. :)

        Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


        I only read formatted code with indentation, so please use PRE tags for code snippets.


        I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


        A 1 Reply Last reply
        0
        • C codie3007

          Hi, In my form based C# app, I use one (of many) option of logging/writing program steps to a text box on the form. It works ok for a while and then starts to slow down as more and more data is passed to it. Is there a way to make this more efficient ? Thanks in advance.

          A Offline
          A Offline
          AspDotNetDev
          wrote on last edited by
          #4

          In addition to what Luc and Dave said, try disabling word wrap. With word wrap enabled, the vertical position of the text depends on the wrapping of text above that line, so removing word wrap should help to prevent that calculation. I just tried that and it seems to not suffer a slowdown.

          [Forum Guidelines]

          1 Reply Last reply
          0
          • D Dave Kreskowiak

            It slows down because you've added a large amount of data to the String that it's showing you. Strings are immutable in .NET, so every time you add data to it, an entirely new string has to be created with the old data copied to it and the new data appended to the end. The answer is simple. Don't use a TextBox. A common replacement for this particular use is a ListBox.

            A guide to posting questions on CodeProject[^]
            Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
                 2006, 2007, 2008
            But no longer in 2009...

            A Offline
            A Offline
            AspDotNetDev
            wrote on last edited by
            #5

            Using a textbox should work, if done correctly. A new string need not be created each time text is appended to a textbox. As Luc said, you can use AppendText to add to a textbox. Textbox probably stores the text as an array of strings (elements are probably split on newline characters), and likely has special getters and setters for the Text property (e.g., if a line was added via AppendText, then add that to the string returned from Text when the getter is called).

            [Forum Guidelines]

            D 1 Reply Last reply
            0
            • L Luc Pattyn

              as Dave said, a ListBox is the preferred Control for showing line-oriented textual information. It would be happy holding thousands of lines of text for you, and continue accepting lots more, whereas a TextBox would come to a stand still. Using TextBox.AppendText("someMore") is slightly better than using TextBox.Text+="someMore", but it too suffers from the quadratic cost explosion. :)

              Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


              I only read formatted code with indentation, so please use PRE tags for code snippets.


              I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


              A Offline
              A Offline
              AspDotNetDev
              wrote on last edited by
              #6

              Luc Pattyn wrote:

              it too suffers from the quadratic cost explosion

              I think that only occurs when you have word wrap set to true. See my answer below.

              [Forum Guidelines]

              L 1 Reply Last reply
              0
              • A AspDotNetDev

                Luc Pattyn wrote:

                it too suffers from the quadratic cost explosion

                I think that only occurs when you have word wrap set to true. See my answer below.

                [Forum Guidelines]

                L Offline
                L Offline
                Luc Pattyn
                wrote on last edited by
                #7

                So I tried again, and yes, my test shows TextBox and ListBox performances are comparable provided you set WordWrap false (the default value is true) and use AppendText. It probably will not suffice to win me over, but it is good to know. Thanks.

                Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                I only read formatted code with indentation, so please use PRE tags for code snippets.


                I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


                1 Reply Last reply
                0
                • A AspDotNetDev

                  Using a textbox should work, if done correctly. A new string need not be created each time text is appended to a textbox. As Luc said, you can use AppendText to add to a textbox. Textbox probably stores the text as an array of strings (elements are probably split on newline characters), and likely has special getters and setters for the Text property (e.g., if a line was added via AppendText, then add that to the string returned from Text when the getter is called).

                  [Forum Guidelines]

                  D Offline
                  D Offline
                  Dave Kreskowiak
                  wrote on last edited by
                  #8

                  aspdotnetdev wrote:

                  A new string need not be created each time text is appended to a textbox. As Luc said, you can use AppendText to add to a textbox

                  ...which creates a new string... AppendText merely takes into account the current values of the Selection properties of the TextBox and replaces that text or appends text to that selection. In any case, the selected string is replaced or text is appended to the String, resulting in a new string being created and parsed when the control needs to render itself. The longer that string gets, the more time it takes to parse it and render what's visible.

                  aspdotnetdev wrote:

                  Textbox probably stores the text as an array of strings

                  No, it doesn't. It uses a String field all the way back up it's inheritance chain.

                  aspdotnetdev wrote:

                  and likely has special getters and setters for the Text property (e.g., if a line was added via AppendText, then add that to the string returned from Text when the getter is called).

                  Nope. If you open Reflector and lok for yourself, it's quite easy to see. Here's the code for the Text property of the TextBox class:

                  Public Overrides Property [Text] As String
                  Get
                  Return MyBase.Text
                  End Get
                  Set(ByVal value As String)
                  MyBase.Text = value
                  Me.selectionSet = False
                  End Set
                  End Property

                  ...and for AppendText (comes from TextBoxBase):

                  Public Sub AppendText(ByVal [text] As String)
                  If ([text].Length > 0) Then
                  Dim num As Integer
                  Dim num2 As Integer
                  Me.GetSelectionStartAndLength(num, num2)
                  Try
                  Dim endPosition As Integer = Me.GetEndPosition
                  Me.SelectInternal(endPosition, endPosition, endPosition)
                  Me.SelectedText = [text]
                  Finally
                  If ((MyBase.Width = 0) OrElse (MyBase.Height = 0)) Then
                  Me.Select(num, num2)
                  End If
                  End Try
                  End If
                  End Sub

                  There's nothing special in there. As for WordWrap, that may or may not be a viable option depending on requirements. TextBox works with monolithic strings no matter what you do. ListBox works with an array of Objects and can handle much more of and more varied content than a TextBox can.

                  A guide to posting que

                  P A L 3 Replies Last reply
                  0
                  • D Dave Kreskowiak

                    aspdotnetdev wrote:

                    A new string need not be created each time text is appended to a textbox. As Luc said, you can use AppendText to add to a textbox

                    ...which creates a new string... AppendText merely takes into account the current values of the Selection properties of the TextBox and replaces that text or appends text to that selection. In any case, the selected string is replaced or text is appended to the String, resulting in a new string being created and parsed when the control needs to render itself. The longer that string gets, the more time it takes to parse it and render what's visible.

                    aspdotnetdev wrote:

                    Textbox probably stores the text as an array of strings

                    No, it doesn't. It uses a String field all the way back up it's inheritance chain.

                    aspdotnetdev wrote:

                    and likely has special getters and setters for the Text property (e.g., if a line was added via AppendText, then add that to the string returned from Text when the getter is called).

                    Nope. If you open Reflector and lok for yourself, it's quite easy to see. Here's the code for the Text property of the TextBox class:

                    Public Overrides Property [Text] As String
                    Get
                    Return MyBase.Text
                    End Get
                    Set(ByVal value As String)
                    MyBase.Text = value
                    Me.selectionSet = False
                    End Set
                    End Property

                    ...and for AppendText (comes from TextBoxBase):

                    Public Sub AppendText(ByVal [text] As String)
                    If ([text].Length > 0) Then
                    Dim num As Integer
                    Dim num2 As Integer
                    Me.GetSelectionStartAndLength(num, num2)
                    Try
                    Dim endPosition As Integer = Me.GetEndPosition
                    Me.SelectInternal(endPosition, endPosition, endPosition)
                    Me.SelectedText = [text]
                    Finally
                    If ((MyBase.Width = 0) OrElse (MyBase.Height = 0)) Then
                    Me.Select(num, num2)
                    End If
                    End Try
                    End If
                    End Sub

                    There's nothing special in there. As for WordWrap, that may or may not be a viable option depending on requirements. TextBox works with monolithic strings no matter what you do. ListBox works with an array of Objects and can handle much more of and more varied content than a TextBox can.

                    A guide to posting que

                    P Offline
                    P Offline
                    Pete OHanlon
                    wrote on last edited by
                    #9

                    Noooooo...... Argggghhhhhh; the horror. VB.NET in a C# forum..... Please Dave, change the reflector output target before you inadvertenly trigger the destruction of the universe.

                    "WPF has many lovers. It's a veritable porn star!" - Josh Smith

                    As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.

                    My blog | My articles | MoXAML PowerToys | Onyx

                    D 1 Reply Last reply
                    0
                    • D Dave Kreskowiak

                      aspdotnetdev wrote:

                      A new string need not be created each time text is appended to a textbox. As Luc said, you can use AppendText to add to a textbox

                      ...which creates a new string... AppendText merely takes into account the current values of the Selection properties of the TextBox and replaces that text or appends text to that selection. In any case, the selected string is replaced or text is appended to the String, resulting in a new string being created and parsed when the control needs to render itself. The longer that string gets, the more time it takes to parse it and render what's visible.

                      aspdotnetdev wrote:

                      Textbox probably stores the text as an array of strings

                      No, it doesn't. It uses a String field all the way back up it's inheritance chain.

                      aspdotnetdev wrote:

                      and likely has special getters and setters for the Text property (e.g., if a line was added via AppendText, then add that to the string returned from Text when the getter is called).

                      Nope. If you open Reflector and lok for yourself, it's quite easy to see. Here's the code for the Text property of the TextBox class:

                      Public Overrides Property [Text] As String
                      Get
                      Return MyBase.Text
                      End Get
                      Set(ByVal value As String)
                      MyBase.Text = value
                      Me.selectionSet = False
                      End Set
                      End Property

                      ...and for AppendText (comes from TextBoxBase):

                      Public Sub AppendText(ByVal [text] As String)
                      If ([text].Length > 0) Then
                      Dim num As Integer
                      Dim num2 As Integer
                      Me.GetSelectionStartAndLength(num, num2)
                      Try
                      Dim endPosition As Integer = Me.GetEndPosition
                      Me.SelectInternal(endPosition, endPosition, endPosition)
                      Me.SelectedText = [text]
                      Finally
                      If ((MyBase.Width = 0) OrElse (MyBase.Height = 0)) Then
                      Me.Select(num, num2)
                      End If
                      End Try
                      End If
                      End Sub

                      There's nothing special in there. As for WordWrap, that may or may not be a viable option depending on requirements. TextBox works with monolithic strings no matter what you do. ListBox works with an array of Objects and can handle much more of and more varied content than a TextBox can.

                      A guide to posting que

                      A Offline
                      A Offline
                      AspDotNetDev
                      wrote on last edited by
                      #10

                      Keep going down the chain. "MyBase.Text" is not a field... it's a property with its own logic. Also, I don't see any string concatenations in that AppendText function you posted.

                      [Forum Guidelines]

                      L D 2 Replies Last reply
                      0
                      • A AspDotNetDev

                        Keep going down the chain. "MyBase.Text" is not a field... it's a property with its own logic. Also, I don't see any string concatenations in that AppendText function you posted.

                        [Forum Guidelines]

                        L Offline
                        L Offline
                        Luc Pattyn
                        wrote on last edited by
                        #11

                        I haven't checked myself, I was told there is a native AppendText function, so one might expect that to be called. Now the real check would be to look at its instructions, i.e. how does it avoid concatenation and quadratic behavior? :)

                        Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                        I only read formatted code with indentation, so please use PRE tags for code snippets.


                        I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


                        A 1 Reply Last reply
                        0
                        • P Pete OHanlon

                          Noooooo...... Argggghhhhhh; the horror. VB.NET in a C# forum..... Please Dave, change the reflector output target before you inadvertenly trigger the destruction of the universe.

                          "WPF has many lovers. It's a veritable porn star!" - Josh Smith

                          As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.

                          My blog | My articles | MoXAML PowerToys | Onyx

                          D Offline
                          D Offline
                          Dave Kreskowiak
                          wrote on last edited by
                          #12

                          Sorry, that's the last setting I used... I'll be a little more careful with the "End of the World" next time. :laugh:

                          A guide to posting questions on CodeProject[^]
                          Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
                               2006, 2007, 2008
                          But no longer in 2009...

                          1 Reply Last reply
                          0
                          • A AspDotNetDev

                            Keep going down the chain. "MyBase.Text" is not a field... it's a property with its own logic. Also, I don't see any string concatenations in that AppendText function you posted.

                            [Forum Guidelines]

                            D Offline
                            D Offline
                            Dave Kreskowiak
                            wrote on last edited by
                            #13

                            Keep going. It's backed by an unmanaged field buried in the Win32 Window class. The actual value is managed by Win32, not .NET, by sending window messages like EM_SETTEXT, EM_REPLACESEL, and the like.

                            aspdotnetdev wrote:

                            Also, I don't see any string concatenations in that AppendText function you posted.

                            I didn't say there was any.

                            A guide to posting questions on CodeProject[^]
                            Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
                                 2006, 2007, 2008
                            But no longer in 2009...

                            A 1 Reply Last reply
                            0
                            • L Luc Pattyn

                              I haven't checked myself, I was told there is a native AppendText function, so one might expect that to be called. Now the real check would be to look at its instructions, i.e. how does it avoid concatenation and quadratic behavior? :)

                              Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                              I only read formatted code with indentation, so please use PRE tags for code snippets.


                              I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


                              A Offline
                              A Offline
                              AspDotNetDev
                              wrote on last edited by
                              #14

                              Luc Pattyn wrote:

                              how does it avoid concatenation and quadratic behavior

                              Perhaps it maintains two data structures. An array where each element holds a line in the string, and a StringBuilder to hold the text that gets appended to Text (so, the only performance hit would be when the Text property is accessed and the StringBuilder has to be serialized to a string). The array of lines would be so the textbox can be painted quickly and the StringBuilder would be so concatenations wouldn't create a performance problem.

                              [Forum Guidelines]

                              L 1 Reply Last reply
                              0
                              • D Dave Kreskowiak

                                Keep going. It's backed by an unmanaged field buried in the Win32 Window class. The actual value is managed by Win32, not .NET, by sending window messages like EM_SETTEXT, EM_REPLACESEL, and the like.

                                aspdotnetdev wrote:

                                Also, I don't see any string concatenations in that AppendText function you posted.

                                I didn't say there was any.

                                A guide to posting questions on CodeProject[^]
                                Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
                                     2006, 2007, 2008
                                But no longer in 2009...

                                A Offline
                                A Offline
                                AspDotNetDev
                                wrote on last edited by
                                #15

                                Dave Kreskowiak wrote:

                                The actual value is managed by Win32, not .NET, by sending window messages like EM_SETTEXT, EM_REPLACESEL, and the like.

                                My guess is that Win32 uses a structure similar to a StringBuilder to ensure append operations are O(1) rather than O(n). For example, they might use mutable strings that double in size each time the capacity is exceeded.

                                Dave Kreskowiak wrote:

                                I didn't say there was any.

                                You said there was nothing funky going on, but you didn't show the whole picture. There are calls to other functions that probably manage things more intelligently than you seem to think append operations are handled.

                                [Forum Guidelines]

                                D 1 Reply Last reply
                                0
                                • A AspDotNetDev

                                  Luc Pattyn wrote:

                                  how does it avoid concatenation and quadratic behavior

                                  Perhaps it maintains two data structures. An array where each element holds a line in the string, and a StringBuilder to hold the text that gets appended to Text (so, the only performance hit would be when the Text property is accessed and the StringBuilder has to be serialized to a string). The array of lines would be so the textbox can be painted quickly and the StringBuilder would be so concatenations wouldn't create a performance problem.

                                  [Forum Guidelines]

                                  L Offline
                                  L Offline
                                  Luc Pattyn
                                  wrote on last edited by
                                  #16

                                  In reality a StringBuilder too behaves quadratically, albeit at a lower frequency: its capacity grows by doubling its size and copying characters any time it is getting full, just like the internal arrays of Lists and other collections. So a number of strings get appended for free, then a new buffer twice the current capacity get allocated and all data copied, etc. Better than copying everything on every new line of text, but still quadratic. While a ListBox is linear, except for the collection holding the references to the items, that too would double its capacity once in a while. :)

                                  Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                                  I only read formatted code with indentation, so please use PRE tags for code snippets.


                                  I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


                                  A 1 Reply Last reply
                                  0
                                  • L Luc Pattyn

                                    In reality a StringBuilder too behaves quadratically, albeit at a lower frequency: its capacity grows by doubling its size and copying characters any time it is getting full, just like the internal arrays of Lists and other collections. So a number of strings get appended for free, then a new buffer twice the current capacity get allocated and all data copied, etc. Better than copying everything on every new line of text, but still quadratic. While a ListBox is linear, except for the collection holding the references to the items, that too would double its capacity once in a while. :)

                                    Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                                    I only read formatted code with indentation, so please use PRE tags for code snippets.


                                    I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


                                    A Offline
                                    A Offline
                                    AspDotNetDev
                                    wrote on last edited by
                                    #17

                                    I am well aware of the performance of StringBuilder. On average, there is only O(1) operation per string append. I would be willing to bet that ListBox has the same performance. I'm guessing it maintains a list internally to store the list of list box items. Lists have the same behavior as a StringBuilder (lists use an array that doubles when capacity is exceeded, just like StringBuilder does).

                                    [Forum Guidelines]

                                    L 1 Reply Last reply
                                    0
                                    • A AspDotNetDev

                                      I am well aware of the performance of StringBuilder. On average, there is only O(1) operation per string append. I would be willing to bet that ListBox has the same performance. I'm guessing it maintains a list internally to store the list of list box items. Lists have the same behavior as a StringBuilder (lists use an array that doubles when capacity is exceeded, just like StringBuilder does).

                                      [Forum Guidelines]

                                      L Offline
                                      L Offline
                                      Luc Pattyn
                                      wrote on last edited by
                                      #18

                                      StringBuilder.Append(string) [and TextBox.AppendText(string) as well] always copies the new characters, StringBuilder uses String.wstrcpy() to do so. OTOH ListBox.Items.Add(item) only copies a reference. :)

                                      Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                                      I only read formatted code with indentation, so please use PRE tags for code snippets.


                                      I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


                                      A 1 Reply Last reply
                                      0
                                      • L Luc Pattyn

                                        StringBuilder.Append(string) [and TextBox.AppendText(string) as well] always copies the new characters, StringBuilder uses String.wstrcpy() to do so. OTOH ListBox.Items.Add(item) only copies a reference. :)

                                        Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                                        I only read formatted code with indentation, so please use PRE tags for code snippets.


                                        I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


                                        A Offline
                                        A Offline
                                        AspDotNetDev
                                        wrote on last edited by
                                        #19

                                        It would still have to render that string, so it would still have to read it. It might have to perform less processing if the string was significantly longer than the viewable area, but that seems like a fringe case. Also, ListBox doesn't have the same features as a TextBox (e.g., the ability to copy all the text at once). I wouldn't base my decision on using TextBox/ListBox on performance... rather, I'd base it on the features of each.

                                        [Forum Guidelines]

                                        L 1 Reply Last reply
                                        0
                                        • A AspDotNetDev

                                          It would still have to render that string, so it would still have to read it. It might have to perform less processing if the string was significantly longer than the viewable area, but that seems like a fringe case. Also, ListBox doesn't have the same features as a TextBox (e.g., the ability to copy all the text at once). I wouldn't base my decision on using TextBox/ListBox on performance... rather, I'd base it on the features of each.

                                          [Forum Guidelines]

                                          L Offline
                                          L Offline
                                          Luc Pattyn
                                          wrote on last edited by
                                          #20

                                          I agree functionality is the determining factor, assuming performance is adequate. The OP stated "logging" and "the textbox slowing down as text gets added" which tells me significantly more text is present than can be seen at any one point in time. BTW: copying all text (or a contiguous block of selected lines) from a ListBox isn't hard at all; it is what I often add to a ListBox-based logging Control. :)

                                          Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                                          I only read formatted code with indentation, so please use PRE tags for code snippets.


                                          I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


                                          A 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups